unc_sdk/store/iterable_map/entry.rs
1use crate::env;
2use borsh::{BorshDeserialize, BorshSerialize};
3
4use super::ValueAndIndex;
5use crate::store::key::ToKey;
6use crate::store::{IterableMap, LookupMap, Vector, ERR_INCONSISTENT_STATE};
7
8/// A view into a single entry in the map, which can be vacant or occupied.
9pub enum Entry<'a, K: 'a, V: 'a, H: 'a>
10where
11 K: BorshSerialize + Ord + Clone,
12 V: BorshSerialize + BorshDeserialize,
13 H: ToKey,
14{
15 Occupied(OccupiedEntry<'a, K, V, H>),
16 Vacant(VacantEntry<'a, K, V, H>),
17}
18
19impl<'a, K, V, H> Entry<'a, K, V, H>
20where
21 K: BorshSerialize + Ord + Clone,
22 V: BorshSerialize + BorshDeserialize,
23 H: ToKey,
24{
25 pub(super) fn new(
26 key: K,
27 keys: &'a mut Vector<K>,
28 values: &'a mut LookupMap<K, ValueAndIndex<V>, H>,
29 ) -> Self {
30 if values.contains_key(&key) {
31 return Self::Occupied(OccupiedEntry { key, keys, values });
32 }
33 Self::Vacant(VacantEntry { key, keys, values })
34 }
35}
36
37impl<'a, K, V, H> Entry<'a, K, V, H>
38where
39 K: BorshSerialize + Ord + Clone,
40 V: BorshSerialize + BorshDeserialize,
41 H: ToKey,
42{
43 /// Returns a reference to this entry's key.
44 ///
45 /// # Examples
46 ///
47 /// ```
48 /// use unc_sdk::store::IterableMap;
49 ///
50 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
51 /// assert_eq!(map.entry("poneyland".to_string()).key(), "poneyland");
52 /// ```
53 pub fn key(&self) -> &K {
54 match self {
55 Entry::Occupied(entry) => entry.key(),
56 Entry::Vacant(entry) => entry.key(),
57 }
58 }
59}
60
61impl<'a, K, V, H> Entry<'a, K, V, H>
62where
63 K: BorshSerialize + BorshDeserialize + Ord + Clone,
64 V: BorshSerialize + BorshDeserialize,
65 H: ToKey,
66{
67 /// Ensures a value is in the entry by inserting the default if empty, and returns
68 /// a mutable reference to the value in the entry.
69 ///
70 /// # Examples
71 ///
72 /// ```
73 /// use unc_sdk::store::IterableMap;
74 ///
75 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
76 ///
77 /// map.entry("poneyland".to_string()).or_insert(3);
78 /// assert_eq!(map["poneyland"], 3);
79 ///
80 /// *map.entry("poneyland".to_string()).or_insert(10) *= 2;
81 /// assert_eq!(map["poneyland"], 6);
82 /// ```
83 pub fn or_insert(self, default: V) -> &'a mut V {
84 self.or_insert_with(|| default)
85 }
86
87 /// Ensures a value is in the entry by inserting the result of the default function if empty,
88 /// and returns a mutable reference to the value in the entry.
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// use unc_sdk::store::IterableMap;
94 ///
95 /// let mut map: IterableMap<String, String> = IterableMap::new(b"m");
96 /// let s = "hoho".to_string();
97 ///
98 /// map.entry("poneyland".to_string()).or_insert_with(|| s);
99 ///
100 /// assert_eq!(map["poneyland"], "hoho".to_string());
101 /// ```
102 pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
103 self.or_insert_with_key(|_| default())
104 }
105
106 /// Ensures a value is in the entry by inserting, if empty, the result of the default function.
107 /// This method allows for generating key-derived values for insertion by providing the default
108 /// function a reference to the key that was moved during the `.entry(key)` method call.
109 ///
110 /// The reference to the moved key is provided so that cloning or copying the key is
111 /// unnecessary, unlike with `.or_insert_with(|| ... )`.
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use unc_sdk::store::IterableMap;
117 ///
118 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
119 ///
120 /// map.entry("poneyland".to_string()).or_insert_with_key(|key| key.chars().count() as u32);
121 ///
122 /// assert_eq!(map["poneyland"], 9);
123 /// ```
124 pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V
125 where
126 K: BorshDeserialize,
127 {
128 match self {
129 Self::Occupied(entry) => entry.into_mut(),
130 Self::Vacant(entry) => {
131 let value = default(entry.key());
132 entry.insert(value)
133 }
134 }
135 }
136
137 /// Ensures a value is in the entry by inserting the default value if empty,
138 /// and returns a mutable reference to the value in the entry.
139 ///
140 /// # Examples
141 ///
142 /// ```
143 /// # fn main() {
144 /// use unc_sdk::store::IterableMap;
145 ///
146 /// let mut map: IterableMap<String, Option<u32>> = IterableMap::new(b"m");
147 /// map.entry("poneyland".to_string()).or_default();
148 ///
149 /// assert_eq!(map["poneyland"], None);
150 /// # }
151 /// ```
152 pub fn or_default(self) -> &'a mut V
153 where
154 V: Default,
155 {
156 match self {
157 Self::Occupied(entry) => entry.into_mut(),
158 Self::Vacant(entry) => entry.insert(Default::default()),
159 }
160 }
161
162 /// Provides in-place mutable access to an occupied entry before any
163 /// potential inserts into the map.
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// use unc_sdk::store::IterableMap;
169 ///
170 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
171 ///
172 /// map.entry("poneyland".to_string())
173 /// .and_modify(|e| { *e += 1 })
174 /// .or_insert(42);
175 /// assert_eq!(map["poneyland"], 42);
176 ///
177 /// map.entry("poneyland".to_string())
178 /// .and_modify(|e| { *e += 1 })
179 /// .or_insert(42);
180 /// assert_eq!(map["poneyland"], 43);
181 /// ```
182 pub fn and_modify<F>(mut self, f: F) -> Self
183 where
184 F: FnOnce(&mut V),
185 {
186 if let Self::Occupied(entry) = &mut self {
187 f(entry.get_mut());
188 }
189 self
190 }
191}
192
193/// View into an occupied entry in a [`IterableMap`](super::IterableMap).
194/// This is part of the [`Entry`] enum.
195pub struct OccupiedEntry<'a, K, V, H>
196where
197 K: BorshSerialize + Ord + Clone,
198 V: BorshSerialize + BorshDeserialize,
199 H: ToKey,
200{
201 key: K,
202 keys: &'a mut Vector<K>,
203 values: &'a mut LookupMap<K, ValueAndIndex<V>, H>,
204}
205
206impl<'a, K, V, H> OccupiedEntry<'a, K, V, H>
207where
208 K: BorshSerialize + Ord + Clone,
209 V: BorshSerialize + BorshDeserialize,
210 H: ToKey,
211{
212 /// Gets a reference to the key in the entry.
213 pub fn key(&self) -> &K {
214 &self.key
215 }
216
217 /// Take the ownership of the key and value from the map.
218 /// TODO: This shared a lot of code with [`super::IterableMap::remove_entry`], it would be best
219 /// to share that code.
220 ///
221 /// # Examples
222 ///
223 /// ```
224 /// use unc_sdk::store::IterableMap;
225 /// use unc_sdk::store::iterable_map::Entry;
226 ///
227 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
228 /// map.entry("poneyland".to_string()).or_insert(12);
229 ///
230 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
231 /// // We delete the entry from the map.
232 /// o.remove_entry();
233 /// }
234 ///
235 /// assert_eq!(map.contains_key("poneyland"), false);
236 /// ```
237 pub fn remove_entry(self) -> (K, V)
238 where
239 K: BorshDeserialize + Ord + Clone,
240 V: BorshDeserialize,
241 {
242 let old_value =
243 self.values.remove(&self.key).unwrap_or_else(|| env::panic_str(ERR_INCONSISTENT_STATE));
244 let last_index = self.keys.len() - 1;
245 self.keys.swap_remove(old_value.key_index);
246
247 IterableMap::remove_entry_helper(self.keys, self.values, old_value.key_index, last_index);
248
249 (self.key, old_value.value)
250 }
251
252 /// Gets a reference to the value in the entry.
253 ///
254 /// # Examples
255 ///
256 /// ```
257 /// use unc_sdk::store::IterableMap;
258 /// use unc_sdk::store::iterable_map::Entry;
259 ///
260 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
261 /// map.entry("poneyland".to_string()).or_insert(12);
262 ///
263 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
264 /// assert_eq!(o.get(), &12);
265 /// }
266 /// ```
267 pub fn get(&self) -> &V {
268 &self.values.get(&self.key).unwrap_or_else(|| env::panic_str(ERR_INCONSISTENT_STATE)).value
269 }
270
271 /// Gets a mutable reference to the value in the entry.
272 ///
273 /// If you need a reference to the `OccupiedEntry` which may outlive the
274 /// destruction of the `Entry` value, see [`into_mut`].
275 ///
276 /// [`into_mut`]: Self::into_mut
277 ///
278 /// # Examples
279 ///
280 /// ```
281 /// use unc_sdk::store::IterableMap;
282 /// use unc_sdk::store::iterable_map::Entry;
283 ///
284 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
285 /// map.entry("poneyland".to_string()).or_insert(12);
286 ///
287 /// assert_eq!(map["poneyland"], 12);
288 /// if let Entry::Occupied(mut o) = map.entry("poneyland".to_string()) {
289 /// *o.get_mut() += 10;
290 /// assert_eq!(*o.get(), 22);
291 ///
292 /// // We can use the same Entry multiple times.
293 /// *o.get_mut() += 2;
294 /// }
295 ///
296 /// assert_eq!(map["poneyland"], 24);
297 /// ```
298 pub fn get_mut(&mut self) -> &mut V {
299 &mut self
300 .values
301 .get_mut(&self.key)
302 .unwrap_or_else(|| env::panic_str(ERR_INCONSISTENT_STATE))
303 .value
304 }
305
306 /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
307 /// with a lifetime bound to the map itself.
308 ///
309 /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
310 ///
311 /// [`get_mut`]: Self::get_mut
312 ///
313 /// # Examples
314 ///
315 /// ```
316 /// use unc_sdk::store::IterableMap;
317 /// use unc_sdk::store::iterable_map::Entry;
318 ///
319 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
320 /// map.entry("poneyland".to_string()).or_insert(12);
321 ///
322 /// assert_eq!(map["poneyland"], 12);
323 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
324 /// *o.into_mut() += 10;
325 /// }
326 ///
327 /// assert_eq!(map["poneyland"], 22);
328 /// ```
329 pub fn into_mut(self) -> &'a mut V {
330 &mut self
331 .values
332 .get_mut(&self.key)
333 .unwrap_or_else(|| env::panic_str(ERR_INCONSISTENT_STATE))
334 .value
335 }
336
337 /// Sets the value of the entry, and returns the entry's old value.
338 ///
339 /// # Examples
340 ///
341 /// ```
342 /// use unc_sdk::store::IterableMap;
343 /// use unc_sdk::store::iterable_map::Entry;
344 ///
345 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
346 /// map.entry("poneyland".to_string()).or_insert(12);
347 ///
348 /// if let Entry::Occupied(mut o) = map.entry("poneyland".to_string()) {
349 /// assert_eq!(o.insert(15), 12);
350 /// }
351 ///
352 /// assert_eq!(map["poneyland"], 15);
353 /// ```
354 pub fn insert(&mut self, value: V) -> V {
355 core::mem::replace(self.get_mut(), value)
356 }
357
358 /// Takes the value out of the entry, and returns it.
359 ///
360 /// # Examples
361 ///
362 /// ```
363 /// use unc_sdk::store::IterableMap;
364 /// use unc_sdk::store::iterable_map::Entry;
365 ///
366 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
367 /// map.entry("poneyland".to_string()).or_insert(12);
368 ///
369 /// if let Entry::Occupied(o) = map.entry("poneyland".to_string()) {
370 /// assert_eq!(o.remove(), 12);
371 /// }
372 ///
373 /// assert_eq!(map.contains_key("poneyland"), false);
374 /// ```
375 pub fn remove(self) -> V
376 where
377 K: BorshDeserialize,
378 {
379 self.remove_entry().1
380 }
381}
382
383/// View into a vacant entry in a [`IterableMap`](super::IterableMap).
384/// This is part of the [`Entry`] enum.
385pub struct VacantEntry<'a, K, V, H>
386where
387 K: BorshSerialize + Ord,
388 V: BorshSerialize,
389 H: ToKey,
390{
391 key: K,
392 values: &'a mut LookupMap<K, ValueAndIndex<V>, H>,
393 keys: &'a mut Vector<K>,
394}
395
396impl<'a, K, V, H> VacantEntry<'a, K, V, H>
397where
398 K: BorshSerialize + Ord,
399 V: BorshSerialize + BorshDeserialize,
400 H: ToKey,
401{
402 /// Gets a reference to the key that would be used when inserting a value
403 /// through the `VacantEntry`.
404 pub fn key(&self) -> &K {
405 &self.key
406 }
407
408 /// Take ownership of the key.
409 ///
410 /// # Examples
411 ///
412 /// ```
413 /// use unc_sdk::store::IterableMap;
414 /// use unc_sdk::store::iterable_map::Entry;
415 ///
416 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
417 ///
418 /// if let Entry::Vacant(v) = map.entry("poneyland".to_string()) {
419 /// v.into_key();
420 /// }
421 /// ```
422 pub fn into_key(self) -> K {
423 self.key
424 }
425
426 /// Sets the value of the entry with the `VacantEntry`'s key,
427 /// and returns a mutable reference to it.
428 ///
429 /// # Examples
430 ///
431 /// ```
432 /// use unc_sdk::store::IterableMap;
433 /// use unc_sdk::store::iterable_map::Entry;
434 ///
435 /// let mut map: IterableMap<String, u32> = IterableMap::new(b"m");
436 ///
437 /// if let Entry::Vacant(o) = map.entry("poneyland".to_string()) {
438 /// o.insert(37);
439 /// }
440 /// assert_eq!(map["poneyland"], 37);
441 /// ```
442 pub fn insert(self, value: V) -> &'a mut V
443 where
444 K: BorshDeserialize + Clone,
445 {
446 // Vacant entry so we know key doesn't exist
447 self.keys.push(self.key().to_owned());
448 let key_index = self.keys.len() - 1;
449 // Guaranteed to be the case as the entry is vacant.
450 &mut self.values.entry(self.key).or_insert(ValueAndIndex { value, key_index }).value
451 }
452}