unc_sdk/store/lookup_map/entry.rs
1use crate::env::abort;
2use crate::utils::CacheEntry;
3
4/// A view into a single entry in the map, which can be vacant or occupied.
5pub enum Entry<'a, K: 'a, V: 'a> {
6 Occupied(OccupiedEntry<'a, K, V>),
7 Vacant(VacantEntry<'a, K, V>),
8}
9
10impl<'a, K, V> Entry<'a, K, V> {
11 /// Returns a reference to this entry's key.
12 ///
13 /// # Examples
14 ///
15 /// ```
16 /// use unc_sdk::store::LookupMap;
17 ///
18 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
19 /// assert_eq!(map.entry("poneyland".to_string()).key(), "poneyland");
20 /// ```
21 pub fn key(&self) -> &K {
22 match self {
23 Entry::Occupied(entry) => entry.key(),
24 Entry::Vacant(entry) => entry.key(),
25 }
26 }
27
28 /// Ensures a value is in the entry by inserting the default if empty, and returns
29 /// a mutable reference to the value in the entry.
30 ///
31 /// # Examples
32 ///
33 /// ```
34 /// use unc_sdk::store::LookupMap;
35 ///
36 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
37 ///
38 /// map.entry("poneyland".to_string()).or_insert(3);
39 /// assert_eq!(map["poneyland"], 3);
40 ///
41 /// *map.entry("poneyland".to_string()).or_insert(10) *= 2;
42 /// assert_eq!(map["poneyland"], 6);
43 /// ```
44 pub fn or_insert(self, default: V) -> &'a mut V {
45 self.or_insert_with(|| default)
46 }
47
48 /// Ensures a value is in the entry by inserting the result of the default function if empty,
49 /// and returns a mutable reference to the value in the entry.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use unc_sdk::store::LookupMap;
55 ///
56 /// let mut map: LookupMap<String, String> = LookupMap::new(b"m");
57 /// let s = "hoho".to_string();
58 ///
59 /// map.entry("poneyland".to_string()).or_insert_with(|| s);
60 ///
61 /// assert_eq!(map["poneyland"], "hoho".to_string());
62 /// ```
63 pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
64 self.or_insert_with_key(|_| default())
65 }
66
67 /// Ensures a value is in the entry by inserting, if empty, the result of the default function.
68 /// This method allows for generating key-derived values for insertion by providing the default
69 /// function a reference to the key that was moved during the `.entry(key)` method call.
70 ///
71 /// The reference to the moved key is provided so that cloning or copying the key is
72 /// unnecessary, unlike with `.or_insert_with(|| ... )`.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// use unc_sdk::store::LookupMap;
78 ///
79 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
80 ///
81 /// map.entry("poneyland".to_string()).or_insert_with_key(|key| key.chars().count() as u32);
82 ///
83 /// assert_eq!(map["poneyland"], 9);
84 /// ```
85 pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
86 match self {
87 Self::Occupied(entry) => entry.into_mut(),
88 Self::Vacant(entry) => {
89 let value = default(entry.key());
90 entry.insert(value)
91 }
92 }
93 }
94
95 /// Ensures a value is in the entry by inserting the default value if empty,
96 /// and returns a mutable reference to the value in the entry.
97 ///
98 /// # Examples
99 ///
100 /// ```
101 /// # fn main() {
102 /// use unc_sdk::store::LookupMap;
103 ///
104 /// let mut map: LookupMap<String, Option<u32>> = LookupMap::new(b"m");
105 /// map.entry("poneyland".to_string()).or_default();
106 ///
107 /// assert_eq!(map["poneyland"], None);
108 /// # }
109 /// ```
110 pub fn or_default(self) -> &'a mut V
111 where
112 V: Default,
113 {
114 match self {
115 Self::Occupied(entry) => entry.into_mut(),
116 Self::Vacant(entry) => entry.insert(Default::default()),
117 }
118 }
119
120 /// Provides in-place mutable access to an occupied entry before any
121 /// potential inserts into the map.
122 ///
123 /// # Examples
124 ///
125 /// ```
126 /// use unc_sdk::store::LookupMap;
127 ///
128 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
129 ///
130 /// map.entry("poneyland".to_string())
131 /// .and_modify(|e| { *e += 1 })
132 /// .or_insert(42);
133 /// assert_eq!(map["poneyland"], 42);
134 ///
135 /// map.entry("poneyland".to_string())
136 /// .and_modify(|e| { *e += 1 })
137 /// .or_insert(42);
138 /// assert_eq!(map["poneyland"], 43);
139 /// ```
140 pub fn and_modify<F>(mut self, f: F) -> Self
141 where
142 F: FnOnce(&mut V),
143 {
144 if let Self::Occupied(entry) = &mut self {
145 f(entry.get_mut());
146 }
147 self
148 }
149}
150
151/// View into an occupied entry in a [`LookupMap`](super::LookupMap).
152/// This is part of the [`Entry`] enum.
153pub struct OccupiedEntry<'a, K, V> {
154 pub(super) key: K,
155 pub(super) entry: &'a mut CacheEntry<V>,
156}
157
158impl<'a, K, V> OccupiedEntry<'a, K, V> {
159 /// Gets a reference to the key in the entry.
160 pub fn key(&self) -> &K {
161 &self.key
162 }
163
164 /// Take the ownership of the key and value from the map.
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// use unc_sdk::store::LookupMap;
170 /// use unc_sdk::store::lookup_map::Entry;
171 ///
172 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
173 /// map.entry("poneyland".to_string()).or_insert(12);
174 ///
175 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
176 /// // We delete the entry from the map.
177 /// o.remove_entry();
178 /// }
179 ///
180 /// assert_eq!(map.contains_key("poneyland"), false);
181 /// ```
182 pub fn remove_entry(self) -> (K, V) {
183 // OnceCell guaranteed to be filled and value to be `Some` in occupied entry
184 let value = self.entry.value_mut().take().unwrap_or_else(|| abort());
185
186 (self.key, value)
187 }
188
189 /// Gets a reference to the value in the entry.
190 ///
191 /// # Examples
192 ///
193 /// ```
194 /// use unc_sdk::store::LookupMap;
195 /// use unc_sdk::store::lookup_map::Entry;
196 ///
197 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
198 /// map.entry("poneyland".to_string()).or_insert(12);
199 ///
200 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
201 /// assert_eq!(o.get(), &12);
202 /// }
203 /// ```
204 pub fn get(&self) -> &V {
205 // Value guaranteed to be `Some` as it's occupied
206 self.entry.value().as_ref().unwrap_or_else(|| abort())
207 }
208
209 /// Gets a mutable reference to the value in the entry.
210 ///
211 /// If you need a reference to the `OccupiedEntry` which may outlive the
212 /// destruction of the `Entry` value, see [`into_mut`].
213 ///
214 /// [`into_mut`]: Self::into_mut
215 ///
216 /// # Examples
217 ///
218 /// ```
219 /// use unc_sdk::store::LookupMap;
220 /// use unc_sdk::store::lookup_map::Entry;
221 ///
222 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
223 /// map.entry("poneyland".to_string()).or_insert(12);
224 ///
225 /// assert_eq!(map["poneyland"], 12);
226 /// if let Entry::Occupied(mut o) = map.entry("poneyland".to_string()) {
227 /// *o.get_mut() += 10;
228 /// assert_eq!(*o.get(), 22);
229 ///
230 /// // We can use the same Entry multiple times.
231 /// *o.get_mut() += 2;
232 /// }
233 ///
234 /// assert_eq!(map["poneyland"], 24);
235 /// ```
236 pub fn get_mut(&mut self) -> &mut V {
237 // Value guaranteed to be `Some` as it's occupied
238 self.entry.value_mut().as_mut().unwrap_or_else(|| abort())
239 }
240
241 /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
242 /// with a lifetime bound to the map itself.
243 ///
244 /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
245 ///
246 /// [`get_mut`]: Self::get_mut
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// use unc_sdk::store::LookupMap;
252 /// use unc_sdk::store::lookup_map::Entry;
253 ///
254 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
255 /// map.entry("poneyland".to_string()).or_insert(12);
256 ///
257 /// assert_eq!(map["poneyland"], 12);
258 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
259 /// *o.into_mut() += 10;
260 /// }
261 ///
262 /// assert_eq!(map["poneyland"], 22);
263 /// ```
264 pub fn into_mut(self) -> &'a mut V {
265 // If entry is occupied, value is guaranteed to be `Some`
266 self.entry.value_mut().as_mut().unwrap_or_else(|| abort())
267 }
268
269 /// Sets the value of the entry, and returns the entry's old value.
270 ///
271 /// # Examples
272 ///
273 /// ```
274 /// use unc_sdk::store::LookupMap;
275 /// use unc_sdk::store::lookup_map::Entry;
276 ///
277 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
278 /// map.entry("poneyland".to_string()).or_insert(12);
279 ///
280 /// if let Entry::Occupied(mut o) = map.entry("poneyland".to_string()) {
281 /// assert_eq!(o.insert(15), 12);
282 /// }
283 ///
284 /// assert_eq!(map["poneyland"], 15);
285 /// ```
286 pub fn insert(&mut self, value: V) -> V {
287 self.entry.replace(Some(value)).unwrap_or_else(|| abort())
288 }
289
290 /// Takes the value out of the entry, and returns it.
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// use unc_sdk::store::LookupMap;
296 /// use unc_sdk::store::lookup_map::Entry;
297 ///
298 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
299 /// map.entry("poneyland".to_string()).or_insert(12);
300 ///
301 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
302 /// assert_eq!(o.remove(), 12);
303 /// }
304 ///
305 /// assert_eq!(map.contains_key("poneyland"), false);
306 /// ```
307 pub fn remove(self) -> V {
308 self.remove_entry().1
309 }
310}
311
312/// View into a vacant entry in a [`LookupMap`](super::LookupMap).
313/// This is part of the [`Entry`] enum.
314pub struct VacantEntry<'a, K, V> {
315 pub(super) key: K,
316 pub(super) entry: &'a mut CacheEntry<V>,
317}
318
319impl<'a, K, V> VacantEntry<'a, K, V> {
320 /// Gets a reference to the key that would be used when inserting a value
321 /// through the `VacantEntry`.
322 pub fn key(&self) -> &K {
323 &self.key
324 }
325
326 /// Take ownership of the key.
327 ///
328 /// # Examples
329 ///
330 /// ```
331 /// use unc_sdk::store::LookupMap;
332 /// use unc_sdk::store::lookup_map::Entry;
333 ///
334 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
335 ///
336 /// if let Entry::Vacant(v) = map.entry("poneyland".to_string()) {
337 /// v.into_key();
338 /// }
339 /// ```
340 pub fn into_key(self) -> K {
341 self.key
342 }
343
344 /// Sets the value of the entry with the `VacantEntry`'s key,
345 /// and returns a mutable reference to it.
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// use unc_sdk::store::LookupMap;
351 /// use unc_sdk::store::lookup_map::Entry;
352 ///
353 /// let mut map: LookupMap<String, u32> = LookupMap::new(b"m");
354 ///
355 /// if let Entry::Vacant(o) = map.entry("poneyland".to_string()) {
356 /// o.insert(37);
357 /// }
358 /// assert_eq!(map["poneyland"], 37);
359 /// ```
360 pub fn insert(self, value: V) -> &'a mut V {
361 self.entry.replace(Some(value));
362 // Insertion done above, cache is filled and the value is Some
363 self.entry.value_mut().as_mut().unwrap_or_else(|| abort())
364 }
365}