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}