iddqd/id_ord_map/
entry.rs

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