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}