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