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}