Skip to main content

iddqd/id_ord_map/
entry.rs

1use super::{IdOrdItem, IdOrdMap, RefMut};
2use crate::support::ItemIndex;
3use core::fmt;
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        match self {
54            Entry::Occupied(entry) => entry.into_mut(),
55            Entry::Vacant(entry) => entry.insert(default),
56        }
57    }
58
59    /// Ensures a value is in the entry by inserting the result of the default
60    /// function if empty, and returns a shared reference to the value in the
61    /// entry.
62    ///
63    /// # Panics
64    ///
65    /// Panics if the key is already present in the map. (The intention is that
66    /// the key should be what was passed into [`IdOrdMap::entry`], but that
67    /// isn't checked in this API due to borrow checker limitations.)
68    #[inline]
69    pub fn or_insert_with_ref<F: FnOnce() -> T>(self, default: F) -> &'a T {
70        match self {
71            Entry::Occupied(entry) => entry.into_ref(),
72            Entry::Vacant(entry) => entry.insert_ref(default()),
73        }
74    }
75
76    /// Ensures a value is in the entry by inserting the result of the default
77    /// function if empty, and returns a mutable reference to the value in the
78    /// entry.
79    ///
80    /// # Panics
81    ///
82    /// Panics if the key is already present in the map. (The intention is that
83    /// the key should be what was passed into [`IdOrdMap::entry`], but that
84    /// isn't checked in this API due to borrow checker limitations.)
85    #[inline]
86    pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> RefMut<'a, T> {
87        match self {
88            Entry::Occupied(entry) => entry.into_mut(),
89            Entry::Vacant(entry) => entry.insert(default()),
90        }
91    }
92
93    /// Provides in-place mutable access to an occupied entry before any
94    /// potential inserts into the map.
95    ///
96    /// # Panics
97    ///
98    /// Panics if `f` changes the item's key, as detected by the `RefMut`.
99    #[inline]
100    pub fn and_modify<F>(self, f: F) -> Self
101    where
102        F: FnOnce(RefMut<'_, T>),
103    {
104        match self {
105            Entry::Occupied(entry) => {
106                {
107                    let map = &mut *entry.map;
108                    let state = map.tables.state().clone();
109                    let item =
110                        map.items.get_mut(entry.index).expect("index is valid");
111                    let hash = map.tables.make_hash(&*item);
112                    f(RefMut::new(state, hash, item));
113                }
114                Entry::Occupied(entry)
115            }
116            Entry::Vacant(entry) => Entry::Vacant(entry),
117        }
118    }
119}
120
121/// A vacant entry.
122pub struct VacantEntry<'a, T: IdOrdItem> {
123    map: &'a mut IdOrdMap<T>,
124}
125
126impl<'a, T: IdOrdItem> fmt::Debug for VacantEntry<'a, T> {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        f.debug_struct("VacantEntry").finish_non_exhaustive()
129    }
130}
131
132impl<'a, T: IdOrdItem> VacantEntry<'a, T> {
133    pub(super) fn new(map: &'a mut IdOrdMap<T>) -> Self {
134        VacantEntry { map }
135    }
136
137    /// Sets the entry to a new value, returning a shared reference to the
138    /// value.
139    ///
140    /// # Panics
141    ///
142    /// Panics if the key is already present in the map. (The intention is that
143    /// the key should be what was passed into [`IdOrdMap::entry`], but that
144    /// isn't checked in this API due to borrow checker limitations.)
145    pub fn insert_ref(self, value: T) -> &'a T {
146        let map = self.map;
147        let Ok(index) = map.insert_unique_impl(value) else {
148            panic!("key already present in map");
149        };
150        map.get_by_index(index).expect("index is known to be valid")
151    }
152
153    /// Sets the entry to a new value, returning a mutable reference to the
154    /// value.
155    pub fn insert(self, value: T) -> RefMut<'a, T> {
156        let map = self.map;
157        let Ok(index) = map.insert_unique_impl(value) else {
158            panic!("key already present in map");
159        };
160        map.get_by_index_mut(index).expect("index is known to be valid")
161    }
162
163    /// Sets the value of the entry, and returns an `OccupiedEntry`.
164    #[inline]
165    pub fn insert_entry(self, value: T) -> OccupiedEntry<'a, T> {
166        let Ok(index) = self.map.insert_unique_impl(value) else {
167            panic!("key already present in map");
168        };
169        OccupiedEntry::new(self.map, index)
170    }
171}
172
173/// A view into an occupied entry in an [`IdOrdMap`]. Part of the [`Entry`]
174/// enum.
175pub struct OccupiedEntry<'a, T: IdOrdItem> {
176    map: &'a mut IdOrdMap<T>,
177    // index is a valid index into the map's internal hash table.
178    index: ItemIndex,
179}
180
181impl<'a, T: IdOrdItem> fmt::Debug for OccupiedEntry<'a, T> {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        f.debug_struct("OccupiedEntry")
184            .field("index", &self.index)
185            .finish_non_exhaustive()
186    }
187}
188
189impl<'a, T: IdOrdItem> OccupiedEntry<'a, T> {
190    pub(super) fn new(map: &'a mut IdOrdMap<T>, index: ItemIndex) -> Self {
191        OccupiedEntry { map, index }
192    }
193
194    /// Gets a reference to the value.
195    ///
196    /// If you need a reference to `T` that may outlive the destruction of the
197    /// `Entry` value, see [`into_ref`](Self::into_ref).
198    pub fn get(&self) -> &T {
199        self.map.get_by_index(self.index).expect("index is known to be valid")
200    }
201
202    /// Gets a mutable reference to the value.
203    ///
204    /// If you need a reference to `T` that may outlive the destruction of the
205    /// `Entry` value, see [`into_mut`](Self::into_mut).
206    pub fn get_mut(&mut self) -> RefMut<'_, T> {
207        self.map
208            .get_by_index_mut(self.index)
209            .expect("index is known to be valid")
210    }
211
212    /// Converts self into a reference to the value.
213    ///
214    /// If you need multiple references to the `OccupiedEntry`, see
215    /// [`get`](Self::get).
216    pub fn into_ref(self) -> &'a T {
217        self.map.get_by_index(self.index).expect("index is known to be valid")
218    }
219
220    /// Converts self into a mutable reference to the value.
221    ///
222    /// If you need multiple references to the `OccupiedEntry`, see
223    /// [`get_mut`](Self::get_mut).
224    pub fn into_mut(self) -> RefMut<'a, T> {
225        self.map
226            .get_by_index_mut(self.index)
227            .expect("index is known to be valid")
228    }
229
230    /// Sets the entry to a new value, returning the old value.
231    ///
232    /// # Panics
233    ///
234    /// Panics if `value.key()` is different from the key of the entry.
235    pub fn insert(&mut self, value: T) -> T {
236        // Note that `replace_at_index` panics if the keys don't match.
237        self.map.replace_at_index(self.index, value)
238    }
239
240    /// Takes ownership of the value from the map.
241    pub fn remove(self) -> T {
242        self.map
243            .remove_by_index(self.index)
244            .expect("index is known to be valid")
245    }
246}