iddqd/id_hash_map/
entry.rs

1use super::{IdHashItem, IdHashMap, RefMut};
2use crate::{
3    DefaultHashBuilder,
4    support::{
5        alloc::{Allocator, Global},
6        borrow::DormantMutRef,
7        map_hash::MapHash,
8    },
9};
10use core::{fmt, hash::BuildHasher};
11
12/// An implementation of the Entry API for [`IdHashMap`].
13pub enum Entry<'a, T: IdHashItem, S = DefaultHashBuilder, A: Allocator = Global>
14{
15    /// A vacant entry.
16    Vacant(VacantEntry<'a, T, S, A>),
17    /// An occupied entry.
18    Occupied(OccupiedEntry<'a, T, S, A>),
19}
20
21impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug for Entry<'a, T, S, A> {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Entry::Vacant(entry) => {
25                f.debug_tuple("Vacant").field(entry).finish()
26            }
27            Entry::Occupied(entry) => {
28                f.debug_tuple("Occupied").field(entry).finish()
29            }
30        }
31    }
32}
33
34impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
35    Entry<'a, T, S, A>
36{
37    /// Ensures a value is in the entry by inserting the default if empty, and
38    /// returns a mutable reference to the value in the entry.
39    ///
40    /// # Panics
41    ///
42    /// Panics if the key hashes to a different value than the one passed
43    /// into [`IdHashMap::entry`].
44    #[inline]
45    pub fn or_insert(self, default: T) -> RefMut<'a, T, S> {
46        match self {
47            Entry::Occupied(entry) => entry.into_mut(),
48            Entry::Vacant(entry) => entry.insert(default),
49        }
50    }
51
52    /// Ensures a value is in the entry by inserting the result of the default
53    /// function if empty, and returns a mutable reference to the value in the
54    /// entry.
55    ///
56    /// # Panics
57    ///
58    /// Panics if the key hashes to a different value than the one passed
59    /// into [`IdHashMap::entry`].
60    #[inline]
61    pub fn or_insert_with<F: FnOnce() -> T>(
62        self,
63        default: F,
64    ) -> RefMut<'a, T, S> {
65        match self {
66            Entry::Occupied(entry) => entry.into_mut(),
67            Entry::Vacant(entry) => entry.insert(default()),
68        }
69    }
70
71    /// Provides in-place mutable access to an occupied entry before any
72    /// potential inserts into the map.
73    #[inline]
74    pub fn and_modify<F>(self, f: F) -> Self
75    where
76        F: FnOnce(RefMut<'_, T, S>),
77    {
78        match self {
79            Entry::Occupied(mut entry) => {
80                f(entry.get_mut());
81                Entry::Occupied(entry)
82            }
83            Entry::Vacant(entry) => Entry::Vacant(entry),
84        }
85    }
86}
87
88/// A vacant entry.
89pub struct VacantEntry<
90    'a,
91    T: IdHashItem,
92    S = DefaultHashBuilder,
93    A: Allocator = Global,
94> {
95    map: DormantMutRef<'a, IdHashMap<T, S, A>>,
96    hash: MapHash<S>,
97}
98
99impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
100    for VacantEntry<'a, T, S, A>
101{
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        f.debug_struct("VacantEntry")
104            .field("hash", &self.hash)
105            .finish_non_exhaustive()
106    }
107}
108
109impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
110    VacantEntry<'a, T, S, A>
111{
112    pub(super) unsafe fn new(
113        map: DormantMutRef<'a, IdHashMap<T, S, A>>,
114        hash: MapHash<S>,
115    ) -> Self {
116        VacantEntry { map, hash }
117    }
118
119    /// Sets the entry to a new value, returning a mutable reference to the
120    /// value.
121    pub fn insert(self, value: T) -> RefMut<'a, T, S> {
122        if !self.hash.is_same_hash(value.key()) {
123            panic!("key hashes do not match");
124        }
125
126        // SAFETY: The safety assumption behind `Self::new` guarantees that the
127        // original reference to the map is not used at this point.
128        let map = unsafe { self.map.awaken() };
129        let Ok(index) = map.insert_unique_impl(value) else {
130            panic!("key already present in map");
131        };
132        map.get_by_index_mut(index).expect("index is known to be valid")
133    }
134
135    /// Sets the value of the entry, and returns an `OccupiedEntry`.
136    #[inline]
137    pub fn insert_entry(mut self, value: T) -> OccupiedEntry<'a, T, S, A> {
138        if !self.hash.is_same_hash(value.key()) {
139            panic!("key hashes do not match");
140        }
141
142        let index = {
143            // SAFETY: The safety assumption behind `Self::new` guarantees that the
144            // original reference to the map is not used at this point.
145            let map = unsafe { self.map.reborrow() };
146            let Ok(index) = map.insert_unique_impl(value) else {
147                panic!("key already present in map");
148            };
149            index
150        };
151
152        // SAFETY: map, as well as anything that was borrowed from it, is
153        // dropped once the above block exits.
154        unsafe { OccupiedEntry::new(self.map, index) }
155    }
156}
157
158/// A view into an occupied entry in an [`IdHashMap`]. Part of the [`Entry`]
159/// enum.
160pub struct OccupiedEntry<
161    'a,
162    T: IdHashItem,
163    S = DefaultHashBuilder,
164    A: Allocator = Global,
165> {
166    map: DormantMutRef<'a, IdHashMap<T, S, A>>,
167    // index is a valid index into the map's internal hash table.
168    index: usize,
169}
170
171impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
172    for OccupiedEntry<'a, T, S, A>
173{
174    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175        f.debug_struct("OccupiedEntry")
176            .field("index", &self.index)
177            .finish_non_exhaustive()
178    }
179}
180
181impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
182    OccupiedEntry<'a, T, S, A>
183{
184    /// # Safety
185    ///
186    /// After self is created, the original reference created by
187    /// `DormantMutRef::new` must not be used.
188    pub(super) unsafe fn new(
189        map: DormantMutRef<'a, IdHashMap<T, S, A>>,
190        index: usize,
191    ) -> Self {
192        OccupiedEntry { map, index }
193    }
194
195    /// Gets a reference to the value.
196    ///
197    /// If you need a reference to `T` that may outlive the destruction of the
198    /// `Entry` value, see [`into_ref`](Self::into_ref).
199    pub fn get(&self) -> &T {
200        // SAFETY: The safety assumption behind `Self::new` guarantees that the
201        // original reference to the map is not used at this point.
202        unsafe { self.map.reborrow_shared() }
203            .get_by_index(self.index)
204            .expect("index is known to be valid")
205    }
206
207    /// Gets a mutable reference to the value.
208    ///
209    /// If you need a reference to `T` that may outlive the destruction of the
210    /// `Entry` value, see [`into_mut`](Self::into_mut).
211    pub fn get_mut(&mut self) -> RefMut<'_, T, S> {
212        // SAFETY: The safety assumption behind `Self::new` guarantees that the
213        // original reference to the map is not used at this point.
214        unsafe { self.map.reborrow() }
215            .get_by_index_mut(self.index)
216            .expect("index is known to be valid")
217    }
218
219    /// Converts self into a reference to the value.
220    ///
221    /// If you need multiple references to the `OccupiedEntry`, see
222    /// [`get`](Self::get).
223    pub fn into_ref(self) -> &'a T {
224        // SAFETY: The safety assumption behind `Self::new` guarantees that the
225        // original reference to the map is not used at this point.
226        unsafe { self.map.awaken() }
227            .get_by_index(self.index)
228            .expect("index is known to be valid")
229    }
230
231    /// Converts self into a mutable reference to the value.
232    ///
233    /// If you need multiple references to the `OccupiedEntry`, see
234    /// [`get_mut`](Self::get_mut).
235    pub fn into_mut(self) -> RefMut<'a, T, S> {
236        // SAFETY: The safety assumption behind `Self::new` guarantees that the
237        // original reference to the map is not used at this point.
238        unsafe { self.map.awaken() }
239            .get_by_index_mut(self.index)
240            .expect("index is known to be valid")
241    }
242
243    /// Sets the entry to a new value, returning the old value.
244    ///
245    /// # Panics
246    ///
247    /// Panics if `value.key()` is different from the key of the entry.
248    pub fn insert(&mut self, value: T) -> T {
249        // SAFETY: The safety assumption behind `Self::new` guarantees that the
250        // original reference to the map is not used at this point.
251        //
252        // Note that `replace_at_index` panics if the keys don't match.
253        unsafe { self.map.reborrow() }.replace_at_index(self.index, value)
254    }
255
256    /// Takes ownership of the value from the map.
257    pub fn remove(mut self) -> T {
258        // SAFETY: The safety assumption behind `Self::new` guarantees that the
259        // original reference to the map is not used at this point.
260        unsafe { self.map.reborrow() }
261            .remove_by_index(self.index)
262            .expect("index is known to be valid")
263    }
264}