type_set/entry.rs
1use crate::{unwrap, Key, Value};
2use std::{
3 any::{type_name, Any, TypeId},
4 collections::btree_map,
5 fmt::{self, Debug, Formatter},
6 marker::PhantomData,
7 ops::{Deref, DerefMut},
8};
9
10/// A view into a single type in the `TypeSet`, which may be either vacant or occupied.
11///
12/// This type is constructed by [`TypeSet::entry`][crate::TypeSet::entry]
13///
14/// ## Examples
15///
16/// This is a somewhat contrived example that demonstrates matching on the [`Entry`]. Often,
17/// [`Entry::or_insert`], [`Entry::or_insert_with`], and [`Entry::and_modify`] can achieve
18/// comparable results. See those functions for further usage examples.
19///
20/// ```rust
21/// use type_set::{TypeSet, entry::Entry};
22/// let mut set = TypeSet::new().with("hello");
23/// let (previous, current) = match set.entry::<&'static str>() {
24/// Entry::Vacant(vacant_entry) => {
25/// let current = vacant_entry.insert("entry was vacant");
26/// (None, current)
27/// }
28///
29/// Entry::Occupied(mut occupied_entry) => {
30/// let previous = occupied_entry.insert("entry was occupied");
31/// (Some(previous), occupied_entry.into_mut())
32/// }
33/// };
34/// assert_eq!(previous, Some("hello"));
35/// assert_eq!(*current, "entry was occupied");
36/// ```
37pub enum Entry<'a, T> {
38 /// A view into the location a T would be stored in the `TypeSet`. See [`VacantEntry`]
39 Vacant(VacantEntry<'a, T>),
40
41 /// A view into the location a T is currently stored in the `TypeSet`. See [`OccupiedEntry`]
42 Occupied(OccupiedEntry<'a, T>),
43}
44
45impl<'a, T: Debug + Any + Send + Sync + 'static> Debug for Entry<'a, T> {
46 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
47 match self {
48 Self::Vacant(vacant_entry) => f.debug_tuple("Vacant").field(vacant_entry).finish(),
49 Self::Occupied(occupied_entry) => {
50 f.debug_tuple("Occupied").field(occupied_entry).finish()
51 }
52 }
53 }
54}
55
56/// A view into a vacant entry in a `TypeSet`.
57///
58/// It is part of the [`Entry`] enum.
59pub struct VacantEntry<'a, T>(
60 pub(super) btree_map::VacantEntry<'a, Key, Value>,
61 PhantomData<T>,
62);
63
64impl<'a, T: Debug + Any + Send + Sync + 'static> Debug for VacantEntry<'a, T> {
65 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
66 write!(f, "VacantEntry<{}>", type_name::<T>())
67 }
68}
69/// A view into the location a T is stored
70pub struct OccupiedEntry<'a, T>(
71 pub(super) btree_map::OccupiedEntry<'a, Key, Value>,
72 PhantomData<T>,
73);
74
75impl<'a, T: Debug + Any + Send + Sync + 'static> Debug for OccupiedEntry<'a, T> {
76 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
77 f.debug_tuple(&format!("OccupiedEntry<{}>", type_name::<T>()))
78 .field(unwrap!(self.0.get().downcast_ref::<T>()))
79 .finish()
80 }
81}
82
83impl<'a, T: Send + Sync + 'static> Entry<'a, T> {
84 /// Ensures a value is in the `Entry` by inserting the provided `default` value if the Entry was
85 /// previously vacant. Returns a mutable reference to the value.
86 ///
87 /// Prefer [`Entry::or_insert_with`] if constructing a T is expensive.
88 ///
89 /// ## Example
90 ///
91 /// ```rust
92 /// let mut set = type_set::TypeSet::new();
93 /// assert_eq!(*set.entry().or_insert("hello"), "hello");
94 /// assert_eq!(set.get::<&'static str>(), Some(&"hello"));
95 /// assert_eq!(*set.entry().or_insert("world"), "hello");
96 /// assert_eq!(set.get::<&'static str>(), Some(&"hello"));
97 /// ```
98 pub fn or_insert(self, default: T) -> &'a mut T {
99 match self {
100 Entry::Vacant(vacant) => vacant.insert(default),
101 Entry::Occupied(occupied) => occupied.into_mut(),
102 }
103 }
104
105 /// Ensures a value is in the `Entry` by inserting the provided value returned by the `default`
106 /// function if the `Entry` was previously vacant. Returns a mutable reference to the value.
107 ///
108 /// Prefer this to [`Entry::or_insert`] if constructing a T is expensive.
109 ///
110 /// ## Example
111 ///
112 /// ```rust
113 /// let mut set = type_set::TypeSet::new();
114 /// assert_eq!(*set.entry().or_insert_with(|| String::from("hello")), "hello");
115 /// assert_eq!(set.get::<String>(), Some(&String::from("hello")));
116 /// assert_eq!(*set.entry::<String>().or_insert_with(|| panic!("never called")), "hello");
117 /// assert_eq!(set.get::<String>(), Some(&String::from("hello")));
118 /// ```
119 pub fn or_insert_with(self, default: impl FnOnce() -> T) -> &'a mut T {
120 match self {
121 Entry::Vacant(vacant) => vacant.insert(default()),
122 Entry::Occupied(occupied) => occupied.into_mut(),
123 }
124 }
125
126 /// Provides in-place mutable access to an occupied entry before any potential inserts into the
127 /// set using [`Entry::or_insert`] or [`Entry::or_insert_with`].
128 ///
129 /// ## Example
130 ///
131 /// ```rust
132 /// let mut set = type_set::TypeSet::new().with(String::from("hello"));
133 /// let value = set.entry::<String>()
134 /// .and_modify(|s| s.push_str(" world"))
135 /// .or_insert_with(|| String::from("greetings"));
136 /// assert_eq!(value, "hello world");
137 ///
138 /// set.take::<String>();
139 /// let value = set.entry::<String>()
140 /// .and_modify(|s| s.push_str(" world"))
141 /// .or_insert_with(|| String::from("greetings"));
142 /// assert_eq!(value, "greetings");
143 /// ```
144 #[must_use]
145 pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self {
146 match self {
147 Entry::Vacant(vacant) => Entry::Vacant(vacant),
148 Entry::Occupied(mut occupied) => {
149 f(occupied.get_mut());
150 Entry::Occupied(occupied)
151 }
152 }
153 }
154
155 /// Remove and return a value from this entry, if occupied.
156 #[must_use]
157 pub fn take(self) -> Option<T> {
158 self.into_occupied().map(OccupiedEntry::remove)
159 }
160
161 /// Returns an `OccupiedEntry` or panic
162 ///
163 /// # Panics
164 ///
165 /// This function will panic if the entry is vacant
166 #[must_use]
167 pub fn unwrap_occupied(self) -> OccupiedEntry<'a, T> {
168 self.into_occupied().unwrap_or_else(|| {
169 panic!(
170 "expected an occupied type-set entry for {}, but was vacant",
171 type_name::<T>()
172 )
173 })
174 }
175
176 /// Returns a `VacantEntry` or panic
177 ///
178 /// # Panics
179 ///
180 /// This function will panic if the entry is occupied
181 #[must_use]
182 pub fn unwrap_vacant(self) -> VacantEntry<'a, T> {
183 self.into_vacant().unwrap_or_else(|| {
184 panic!(
185 "expected a vacant type-set entry for {}, but was occupied",
186 type_name::<T>()
187 )
188 })
189 }
190
191 /// Returns a mutable reference to the contained type, if this entry is occupied
192 #[must_use]
193 pub fn into_mut(self) -> Option<&'a mut T> {
194 self.into_occupied().map(OccupiedEntry::into_mut)
195 }
196
197 /// Returns an [`OccupiedEntry`] or `None` if this entry is vacant.
198 #[must_use]
199 pub fn into_occupied(self) -> Option<OccupiedEntry<'a, T>> {
200 match self {
201 Entry::Occupied(occupied_entry) => Some(occupied_entry),
202 Entry::Vacant(_) => None,
203 }
204 }
205
206 /// Returns a [`VacantEntry`] or `None` if this entry is occupied.
207 #[must_use]
208 pub fn into_vacant(self) -> Option<VacantEntry<'a, T>> {
209 match self {
210 Entry::Occupied(_) => None,
211 Entry::Vacant(vacant_entry) => Some(vacant_entry),
212 }
213 }
214
215 /// Returns whether this `Entry` is a [`VacantEntry`]
216 #[must_use]
217 pub fn is_empty(&self) -> bool {
218 matches!(self, Entry::Vacant(_))
219 }
220
221 /// Insert a value into this [`Entry`].
222 ///
223 /// If the Entry is already an [`OccupiedEntry`], the previously contained value will be
224 /// returned
225 pub fn insert(self, value: T) -> Option<T> {
226 match self {
227 Entry::Vacant(v) => {
228 #[cfg(feature = "log")]
229 log::trace!("inserting {}", type_name::<T>());
230 v.insert(value);
231 None
232 }
233
234 Entry::Occupied(mut o) => {
235 #[cfg(feature = "log")]
236 log::trace!("replacing {}", type_name::<T>());
237 Some(o.insert(value))
238 }
239 }
240 }
241
242 pub(super) fn new(entry: btree_map::Entry<'a, TypeId, Value>) -> Self {
243 match entry {
244 btree_map::Entry::Vacant(vacant) => Self::Vacant(VacantEntry(vacant, PhantomData)),
245 btree_map::Entry::Occupied(occupied) => {
246 Self::Occupied(OccupiedEntry(occupied, PhantomData))
247 }
248 }
249 }
250}
251
252impl<'a, T: Default + Send + Sync + 'static> Entry<'a, T> {
253 /// Ensures a value is in the Entry by inserting the default value if vacant, and returns a
254 /// mutable reference to the value.
255 ///
256 /// Equivalent to `.or_insert_with(Default::default)`
257 ///
258 /// ## Example
259 ///
260 /// ```rust
261 /// let mut set = type_set::TypeSet::new();
262 /// assert_eq!(*set.entry::<&'static str>().or_default(), "");
263 /// set.insert("hello");
264 /// assert_eq!(*set.entry::<&'static str>().or_default(), "hello");
265 /// ```
266 pub fn or_default(self) -> &'a mut T {
267 #[allow(clippy::unwrap_or_default)]
268 // this is the implementation of or_default so it can't call or_default
269 self.or_insert_with(T::default)
270 }
271}
272
273impl<'a, T: Send + Sync + 'static> VacantEntry<'a, T> {
274 /// Sets the value of this entry to the provided `value`
275 pub fn insert(self, value: T) -> &'a mut T {
276 unwrap!(self.0.insert(Value::new(value)).downcast_mut())
277 }
278}
279
280impl<'a, T: Send + Sync + 'static> OccupiedEntry<'a, T> {
281 /// Gets a reference to the value in this entry
282 #[must_use]
283 pub fn get(&self) -> &T {
284 unwrap!(self.0.get().downcast_ref())
285 }
286
287 /// Gets a mutable reference to the value in the entry
288 ///
289 /// If you need a reference to the `OccupiedEntry` that may outlive the
290 /// destruction of the `Entry` value, see [`OccupiedEntry::into_mut`].
291 #[must_use]
292 pub fn get_mut(&mut self) -> &mut T {
293 unwrap!(self.0.get_mut().downcast_mut())
294 }
295
296 /// Sets the value of the entry to `value`, returning the entry's previous value.
297 pub fn insert(&mut self, value: T) -> T {
298 unwrap!(self.0.insert(Value::new(value)).downcast())
299 }
300
301 /// Take ownership of the value from this Entry
302 #[allow(clippy::must_use_candidate)] // sometimes we just want to take the value out and drop it
303 pub fn remove(self) -> T {
304 unwrap!(self.0.remove().downcast())
305 }
306
307 /// Converts the entry into a mutable reference to its value.
308 ///
309 /// If you need multiple references to the `OccupiedEntry`, see [`OccupiedEntry::get_mut`].
310 #[must_use]
311 pub fn into_mut(self) -> &'a mut T {
312 unwrap!(self.0.into_mut().downcast_mut())
313 }
314}
315
316impl<'a, T: Send + Sync + 'static> Deref for OccupiedEntry<'a, T> {
317 type Target = T;
318
319 fn deref(&self) -> &Self::Target {
320 self.get()
321 }
322}
323
324impl<'a, T: Send + Sync + 'static> DerefMut for OccupiedEntry<'a, T> {
325 fn deref_mut(&mut self) -> &mut Self::Target {
326 self.get_mut()
327 }
328}
329
330impl<'a, T: Send + Sync + 'static> From<OccupiedEntry<'a, T>> for Entry<'a, T> {
331 fn from(occupied_entry: OccupiedEntry<'a, T>) -> Self {
332 Self::Occupied(occupied_entry)
333 }
334}
335
336impl<'a, T: Send + Sync + 'static> From<VacantEntry<'a, T>> for Entry<'a, T> {
337 fn from(vacant_entry: VacantEntry<'a, T>) -> Self {
338 Self::Vacant(vacant_entry)
339 }
340}