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 (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                        (hash, dormant)
123                    };
124
125                    // SAFETY: the item above is not used after this point.
126                    let awakened_item = unsafe { dormant.awaken() };
127                    let ref_mut = RefMut::new(hash, awakened_item);
128                    f(ref_mut);
129                }
130                Entry::Occupied(entry)
131            }
132            Entry::Vacant(entry) => Entry::Vacant(entry),
133        }
134    }
135}
136
137/// A vacant entry.
138pub struct VacantEntry<'a, T: IdOrdItem> {
139    map: DormantMutRef<'a, IdOrdMap<T>>,
140}
141
142impl<'a, T: IdOrdItem> fmt::Debug for VacantEntry<'a, T> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        f.debug_struct("VacantEntry").finish_non_exhaustive()
145    }
146}
147
148impl<'a, T: IdOrdItem> VacantEntry<'a, T> {
149    pub(super) unsafe fn new(map: DormantMutRef<'a, IdOrdMap<T>>) -> Self {
150        VacantEntry { map }
151    }
152
153    /// Sets the entry to a new value, returning a shared reference to the
154    /// value.
155    ///
156    /// # Panics
157    ///
158    /// Panics if the key is already present in the map. (The intention is that
159    /// the key should be what was passed into [`IdOrdMap::entry`], but that
160    /// isn't checked in this API due to borrow checker limitations.)
161    pub fn insert_ref(self, value: T) -> &'a T {
162        // SAFETY: The safety assumption behind `Self::new` guarantees that the
163        // original reference to the map is not used at this point.
164        let map = unsafe { self.map.awaken() };
165        let Ok(index) = map.insert_unique_impl(value) else {
166            panic!("key already present in map");
167        };
168        map.get_by_index(index).expect("index is known to be valid")
169    }
170
171    /// Sets the entry to a new value, returning a mutable reference to the
172    /// value.
173    pub fn insert(self, value: T) -> RefMut<'a, T>
174    where
175        T::Key<'a>: Hash,
176    {
177        // SAFETY: The safety assumption behind `Self::new` guarantees that the
178        // original reference to the map is not used at this point.
179        let map = unsafe { self.map.awaken() };
180        let Ok(index) = map.insert_unique_impl(value) else {
181            panic!("key already present in map");
182        };
183        map.get_by_index_mut(index).expect("index is known to be valid")
184    }
185
186    /// Sets the value of the entry, and returns an `OccupiedEntry`.
187    #[inline]
188    pub fn insert_entry(mut self, value: T) -> OccupiedEntry<'a, T> {
189        let index = {
190            // SAFETY: The safety assumption behind `Self::new` guarantees that the
191            // original reference to the map is not used at this point.
192            let map = unsafe { self.map.reborrow() };
193            let Ok(index) = map.insert_unique_impl(value) else {
194                panic!("key already present in map");
195            };
196            index
197        };
198
199        // SAFETY: map, as well as anything that was borrowed from it, is
200        // dropped once the above block exits.
201        unsafe { OccupiedEntry::new(self.map, index) }
202    }
203}
204
205/// A view into an occupied entry in an [`IdOrdMap`]. Part of the [`Entry`]
206/// enum.
207pub struct OccupiedEntry<'a, T: IdOrdItem> {
208    map: DormantMutRef<'a, IdOrdMap<T>>,
209    // index is a valid index into the map's internal hash table.
210    index: usize,
211}
212
213impl<'a, T: IdOrdItem> fmt::Debug for OccupiedEntry<'a, T> {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        f.debug_struct("OccupiedEntry")
216            .field("index", &self.index)
217            .finish_non_exhaustive()
218    }
219}
220
221impl<'a, T: IdOrdItem> OccupiedEntry<'a, T> {
222    /// # Safety
223    ///
224    /// After self is created, the original reference created by
225    /// `DormantMutRef::new` must not be used.
226    pub(super) unsafe fn new(
227        map: DormantMutRef<'a, IdOrdMap<T>>,
228        index: usize,
229    ) -> Self {
230        OccupiedEntry { map, index }
231    }
232
233    /// Gets a reference to the value.
234    ///
235    /// If you need a reference to `T` that may outlive the destruction of the
236    /// `Entry` value, see [`into_ref`](Self::into_ref).
237    pub fn get(&self) -> &T {
238        // SAFETY: The safety assumption behind `Self::new` guarantees that the
239        // original reference to the map is not used at this point.
240        unsafe { self.map.reborrow_shared() }
241            .get_by_index(self.index)
242            .expect("index is known to be valid")
243    }
244
245    /// Gets a mutable reference to the value.
246    ///
247    /// If you need a reference to `T` that may outlive the destruction of the
248    /// `Entry` value, see [`into_mut`](Self::into_mut).
249    pub fn get_mut<'b>(&'b mut self) -> RefMut<'b, T>
250    where
251        T::Key<'b>: Hash,
252    {
253        // SAFETY: The safety assumption behind `Self::new` guarantees that the
254        // original reference to the map is not used at this point.
255        unsafe { self.map.reborrow() }
256            .get_by_index_mut(self.index)
257            .expect("index is known to be valid")
258    }
259
260    /// Converts self into a reference to the value.
261    ///
262    /// If you need multiple references to the `OccupiedEntry`, see
263    /// [`get`](Self::get).
264    pub fn into_ref(self) -> &'a T {
265        // SAFETY: The safety assumption behind `Self::new` guarantees that the
266        // original reference to the map is not used at this point.
267        unsafe { self.map.awaken() }
268            .get_by_index(self.index)
269            .expect("index is known to be valid")
270    }
271
272    /// Converts self into a mutable reference to the value.
273    ///
274    /// If you need multiple references to the `OccupiedEntry`, see
275    /// [`get_mut`](Self::get_mut).
276    pub fn into_mut(self) -> RefMut<'a, T>
277    where
278        T::Key<'a>: Hash,
279    {
280        // SAFETY: The safety assumption behind `Self::new` guarantees that the
281        // original reference to the map is not used at this point.
282        unsafe { self.map.awaken() }
283            .get_by_index_mut(self.index)
284            .expect("index is known to be valid")
285    }
286
287    /// Sets the entry to a new value, returning the old value.
288    ///
289    /// # Panics
290    ///
291    /// Panics if `value.key()` is different from the key of the entry.
292    pub fn insert(&mut self, value: T) -> T {
293        // SAFETY: The safety assumption behind `Self::new` guarantees that the
294        // original reference to the map is not used at this point.
295        //
296        // Note that `replace_at_index` panics if the keys don't match.
297        unsafe { self.map.reborrow() }.replace_at_index(self.index, value)
298    }
299
300    /// Takes ownership of the value from the map.
301    pub fn remove(mut self) -> T {
302        // SAFETY: The safety assumption behind `Self::new` guarantees that the
303        // original reference to the map is not used at this point.
304        unsafe { self.map.reborrow() }
305            .remove_by_index(self.index)
306            .expect("index is known to be valid")
307    }
308}