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