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}