extract_map/
entry.rs

1//! An implementation of the Entry API for [`ExtractMap`].
2
3use std::hash::{BuildHasher, Hash};
4
5use crate::ExtractKey;
6
7use super::ExtractMap;
8use hashbrown::hash_table::{
9    Entry as RawEntry, OccupiedEntry as RawOccupiedEntry, VacantEntry as RawVacantEntry,
10};
11
12macro_rules! forward_debug {
13    ($type_name:ident) => {
14        impl<'a, V: std::fmt::Debug> std::fmt::Debug for $type_name<'a, V> {
15            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16                self.0.fmt(f)
17            }
18        }
19    };
20}
21
22impl<K, V, S> ExtractMap<K, V, S>
23where
24    K: Hash + Eq,
25    V: ExtractKey<K>,
26    S: BuildHasher,
27{
28    /// Gets the given key’s corresponding entry in the map for in-place manipulation.
29    pub fn entry(&mut self, key: &K) -> Entry<'_, V> {
30        Entry::from_raw(self.raw_entry(key))
31    }
32}
33
34/// A view into a single entry in a table, which may either be vacant or occupied.
35///
36/// This enum is constructed from [`ExtractMap::entry`].
37#[derive(Debug)]
38pub enum Entry<'a, V> {
39    /// An occupied entry.
40    Occupied(OccupiedEntry<'a, V>),
41    /// A vacant entry.
42    Vacant(VacantEntry<'a, V>),
43}
44
45impl<'a, V> Entry<'a, V> {
46    fn from_raw(raw: RawEntry<'a, V>) -> Self {
47        match raw {
48            RawEntry::Occupied(raw_entry) => Entry::Occupied(OccupiedEntry(raw_entry)),
49            RawEntry::Vacant(raw_entry) => Entry::Vacant(VacantEntry(raw_entry)),
50        }
51    }
52
53    fn into_raw(self) -> RawEntry<'a, V> {
54        match self {
55            Entry::Occupied(entry) => RawEntry::Occupied(entry.0),
56            Entry::Vacant(entry) => RawEntry::Vacant(entry.0),
57        }
58    }
59
60    /// Sets the value of the entry, replacing any existing value if there is one, and returns an [`OccupiedEntry`].
61    ///
62    /// # Example
63    ///
64    /// ```
65    /// use extract_map::ExtractMap;
66    /// # use extract_map::doc_examples::User;
67    ///
68    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
69    /// map.insert(User { id: 1, name: "Cat" });
70    ///
71    /// let entry = map.entry(&1).insert(User { id: 1, name: "Fox" });
72    /// assert_eq!(entry.get(), &User { id: 1, name: "Fox" });
73    /// ```
74    pub fn insert(self, value: V) -> OccupiedEntry<'a, V> {
75        OccupiedEntry(self.into_raw().insert(value))
76    }
77
78    /// Ensures a value is in the entry by inserting if it was vacant.
79    ///
80    /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry.
81    ///
82    /// # Example
83    ///
84    /// ```
85    /// use extract_map::ExtractMap;
86    /// # use extract_map::doc_examples::User;
87    ///
88    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
89    ///
90    /// // Inserts new entry, as the map is empty.
91    /// let entry = map.entry(&1).or_insert(User { id: 1, name: "Fox" });
92    /// assert_eq!(entry.get(), &User { id: 1, name: "Fox" });
93    ///
94    /// // Does not insert new entry, as there is already a user with ID 1.
95    /// let entry = map.entry(&1).or_insert(User { id: 1, name: "Cat" });
96    /// assert_eq!(entry.get(), &User { id: 1, name: "Fox" });
97    /// ```
98    pub fn or_insert(self, default: V) -> OccupiedEntry<'a, V> {
99        OccupiedEntry(self.into_raw().or_insert(default))
100    }
101
102    /// Ensures a value is in the entry by inserting the result of the function if it was vacant.
103    ///
104    /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry.
105    ///
106    /// # Example
107    ///
108    /// ```
109    /// use extract_map::ExtractMap;
110    /// # use extract_map::doc_examples::User;
111    ///
112    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
113    ///
114    /// // Inserts new entry, as the map is empty.
115    /// let entry = map.entry(&1).or_insert_with(|| User { id: 1, name: "Fox" });
116    /// assert_eq!(entry.get(), &User { id: 1, name: "Fox" });
117    ///
118    /// // Does not insert new entry, as there is already a user with ID 1.
119    /// let entry = map.entry(&1).or_insert_with(|| User { id: 1, name: "Cat" });
120    /// assert_eq!(entry.get(), &User { id: 1, name: "Fox" });
121    /// ```
122    pub fn or_insert_with(self, default: impl FnOnce() -> V) -> OccupiedEntry<'a, V> {
123        OccupiedEntry(self.into_raw().or_insert_with(default))
124    }
125
126    /// Provides in-place mutable access to an occupied entry, does nothing for a vacant entry.
127    ///
128    /// # Example
129    ///
130    /// ```
131    /// use extract_map::ExtractMap;
132    /// # use extract_map::doc_examples::User;
133    ///
134    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
135    ///
136    /// map.insert(User { id: 1, name: "Cat"});
137    /// map.entry(&1).and_modify(|user| user.name = "Fox");
138    ///
139    /// assert_eq!(map.get(&1), Some(&User { id: 1, name: "Fox"}));
140    /// ```
141    #[allow(clippy::return_self_not_must_use)]
142    pub fn and_modify(self, f: impl FnOnce(&mut V)) -> Self {
143        Self::from_raw(self.into_raw().and_modify(f))
144    }
145}
146
147/// A view into an occupied entry in an [`ExtractMap`]. It is part of the [`Entry`] enum.
148pub struct OccupiedEntry<'a, V>(RawOccupiedEntry<'a, V>);
149
150forward_debug!(OccupiedEntry);
151
152impl<'a, V> OccupiedEntry<'a, V> {
153    /// Removes the value from the map.
154    ///
155    /// # Example
156    /// ```
157    /// use extract_map::{ExtractMap, entry::Entry};
158    /// # use extract_map::doc_examples::User;
159    ///
160    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
161    /// map.insert(User { id: 1, name: "Fox" });
162    ///
163    /// if let Entry::Occupied(entry) = map.entry(&1) {
164    ///     entry.remove();
165    /// }
166    ///
167    /// assert!(map.is_empty());
168    /// ```
169    #[allow(clippy::must_use_candidate)]
170    pub fn remove(self) -> V {
171        self.0.remove().0
172    }
173
174    /// Gets a reference to the value from the map.
175    ///
176    /// # Example
177    ///
178    /// ```
179    /// use extract_map::{ExtractMap, entry::Entry};
180    /// # use extract_map::doc_examples::User;
181    ///
182    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
183    /// map.insert(User { id: 1, name: "Cat" });
184    ///
185    /// if let Entry::Occupied(entry) = map.entry(&1) {
186    ///     assert_eq!(entry.get(), &User { id: 1, name: "Cat" });
187    /// }
188    /// ```
189    #[must_use]
190    pub fn get(&self) -> &V {
191        self.0.get()
192    }
193
194    /// Gets a mutable reference to the value from the map.
195    ///
196    /// If you need a mutable reference borrowing from the map, instead of the entry, use [`Self::into_mut`].
197    ///
198    /// # Example
199    ///
200    /// ```
201    /// use extract_map::{ExtractMap, entry::Entry};
202    /// # use extract_map::doc_examples::User;
203    ///
204    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
205    /// map.insert(User { id: 1, name: "Cat" });
206    ///
207    /// if let Entry::Occupied(mut entry) = map.entry(&1) {
208    ///     entry.get_mut().name = "Fox";
209    /// }
210    ///
211    /// assert_eq!(map.get(&1), Some(&User { id: 1, name: "Fox" }));
212    /// ```
213    pub fn get_mut(&mut self) -> &mut V {
214        self.0.get_mut()
215    }
216
217    /// Converts the [`OccupiedEntry`] into a mutable reference to the value from the map.
218    ///
219    /// If you need multiple mutable references to the entry, use [`Self::get_mut`].
220    ///
221    /// # Example
222    ///
223    /// ```
224    /// use extract_map::{ExtractMap, entry::Entry};
225    /// # use extract_map::doc_examples::User;
226    ///
227    /// let mut map: ExtractMap<u64, User> = ExtractMap::new();
228    /// map.insert(User { id: 1, name: "Cat" });
229    ///
230    /// let user_ref = if let Entry::Occupied(entry) = map.entry(&1) {
231    ///     entry.into_mut()
232    /// } else {
233    ///     unreachable!()
234    /// };
235    ///
236    /// user_ref.name = "Fox";
237    /// assert_eq!(map.get(&1), Some(&User { id: 1, name: "Fox" }));
238    /// ```
239    #[must_use]
240    pub fn into_mut(self) -> &'a mut V {
241        self.0.into_mut()
242    }
243
244    /// Sets the value of the entry, and returns the entry’s old value.
245    ///
246    /// This is equivalent to [`std::mem::replace`] with [`Self::get_mut`].
247    pub fn insert(&mut self, value: V) -> V {
248        std::mem::replace(self.0.get_mut(), value)
249    }
250}
251
252/// A view into a vacant entry in an [`ExtractMap`]. It is part of the [`Entry`] enum.
253pub struct VacantEntry<'a, V>(RawVacantEntry<'a, V>);
254
255forward_debug!(VacantEntry);
256
257impl<'a, V> VacantEntry<'a, V> {
258    /// Sets the value of the entry with the [`VacantEntry`]’s key, and returns an [`OccupiedEntry`].
259    pub fn insert(self, value: V) -> OccupiedEntry<'a, V> {
260        OccupiedEntry(self.0.insert(value))
261    }
262}