erased_set/lib.rs
1//! # 🦀 `ErasedSet`
2//!
3//! You may be looking for:
4//!
5//! - [Git repository](https://github.com/malobre/erased_set)
6//! - [Crates.io](https://crates.io/crates/erased_set)
7//!
8//! ---
9//!
10//! This crate provides a new collection: the [`ErasedSet`].
11//! It allows storing different types in a single set (as long as they implement [`Any`]).
12//!
13//! [`Any`]: ::core::any::Any
14//!
15//! ## Example
16//!
17//! ```
18//! # #[derive(Debug, PartialEq)]
19//! # struct ClickEvent(u32, u32);
20//! # #[derive(Debug, PartialEq)]
21//! # struct KeyDownEvent(char);
22//! #
23//! use erased_set::ErasedSet;
24//!
25//! let mut set = ErasedSet::new();
26//! set.insert(ClickEvent(128, 256));
27//! set.insert(KeyDownEvent('z'));
28//!
29//! assert_eq!(set.get::<ClickEvent>(), Some(&ClickEvent(128, 256)));
30//!
31//! assert_eq!(set.insert(KeyDownEvent('e')), Some(KeyDownEvent('z')));
32//!
33//! set.remove::<ClickEvent>();
34//!
35//! assert_eq!(set.len(), 1);
36//! ```
37//!
38//! ## Features
39//!
40//! | name | default ? | description |
41//! | ----------- | --------- | ------------------------- |
42//! | `send` | yes | Enables [`ErasedSendSet`] |
43//! | `sync` | yes | Enables [`ErasedSyncSet`] |
44//!
45//! ## `no_std` support
46//!
47//! This crate is `no_std` compatible, however it still requires `alloc`.
48
49#![no_std]
50
51extern crate alloc;
52
53/// Implement an erased set with the specified bounds.
54///
55/// # Syntax
56///
57/// ```rust,ignore
58/// impl_erased_set! {
59/// [pub] struct NAME: Any [+ BOUNDS ...];
60/// }
61/// ```
62///
63/// # Example
64///
65/// ```rust,ignore
66/// erased_set::impl_erased_set! {
67/// /// A set of erased types.
68/// #[derive(Debug, Default)]
69/// pub struct ErasedSet: Any;
70/// }
71/// ```
72// This macro is not currently public because trait objects for multiple traits are not currently
73// supported, see <https://github.com/rust-lang/rfcs/issues/2035> for more details.
74macro_rules! impl_erased_set {
75 (
76 $(#[$attr:meta])*
77 $vis:vis struct $name:ident: Any $(+ $bounds:tt)*;
78 ) => {
79 $(#[$attr])*
80 $vis struct $name {
81 #[doc(hidden)]
82 inner: ::alloc::collections::BTreeMap<
83 ::core::any::TypeId,
84 ::alloc::boxed::Box<dyn ::core::any::Any $(+ $bounds)*>,
85 >,
86 #[doc(hidden)]
87 #[cfg(debug_assertions)]
88 debug_type_names: ::alloc::collections::BTreeMap<
89 ::core::any::TypeId,
90 &'static str
91 >,
92 }
93
94 impl $name {
95 #[doc = concat!("Creates an empty [`", stringify!($name), "`].")]
96 ///
97 /// The set is initially created with a capacity of 0, so it will not allocate
98 /// until it is first inserted into.
99 ///
100 /// # Examples
101 ///
102 /// ```
103 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
104 ///
105 #[doc = concat!("let set = ", stringify!($name), "::new();")]
106 /// ```
107 #[must_use]
108 pub fn new() -> Self {
109 Self {
110 inner: ::alloc::collections::BTreeMap::new(),
111 #[cfg(debug_assertions)]
112 debug_type_names: ::alloc::collections::BTreeMap::new(),
113 }
114 }
115
116 /// Returns `true` if the set contains no instances of any type.
117 ///
118 /// # Examples
119 ///
120 /// ```
121 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
122 ///
123 #[doc = concat!("let set = ", stringify!($name), "::new();")]
124 /// assert!(set.is_empty());
125 /// ```
126 #[must_use]
127 pub fn is_empty(&self) -> bool {
128 self.inner.is_empty()
129 }
130
131 /// Returns the number of types in the set.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
137 ///
138 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
139 /// assert_eq!(set.len(), 0);
140 /// set.insert("a");
141 /// assert_eq!(set.len(), 1);
142 /// ```
143 #[must_use]
144 pub fn len(&self) -> usize {
145 self.inner.len()
146 }
147
148 /// Clears the set. Keep allocated memory for reuse.
149 ///
150 /// # Examples
151 ///
152 /// ```
153 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
154 ///
155 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
156 /// set.insert("a");
157 /// set.clear();
158 /// assert!(set.is_empty());
159 /// ```
160 pub fn clear(&mut self) {
161 self.inner.clear();
162 }
163
164 /// Returns `true` if the set contains an instance of `T`.
165 ///
166 /// # Examples
167 ///
168 /// ```
169 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
170 ///
171 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
172 /// set.insert("a");
173 /// assert!(set.contains::<&str>());
174 /// ```
175 #[must_use]
176 pub fn contains<T>(&self) -> bool
177 where
178 T: ::core::any::Any,
179 {
180 self.inner.contains_key(&::core::any::TypeId::of::<T>())
181 }
182
183 /// Returns a reference to an instance of `T`.
184 ///
185 /// If the set does not have an instance of `T`, [`None`] is returned.
186 ///
187 /// # Examples
188 ///
189 /// ```
190 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
191 ///
192 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
193 /// set.insert("a");
194 /// assert_eq!(set.get::<&str>(), Some(&"a"));
195 /// assert_eq!(set.get::<bool>(), None);
196 /// ```
197 #[must_use]
198 pub fn get<T>(&self) -> Option<&T>
199 where
200 T: ::core::any::Any $(+ $bounds)*,
201 {
202 use ::core::any::{Any, TypeId};
203 use ::alloc::boxed::Box;
204
205 self.inner
206 .get(&TypeId::of::<T>())
207 .map(|boxed_any: &Box<dyn Any $(+ $bounds)*>| {
208 // Sanity check
209 debug_assert!(boxed_any.as_ref().is::<T>());
210
211 let ptr = (boxed_any.as_ref() as *const dyn Any).cast::<T>();
212
213 unsafe { &*ptr }
214 })
215 }
216
217 /// Inserts the given `value` into the set if it is not present, then
218 /// returns a reference to the value in the set.
219 ///
220 /// # Examples
221 ///
222 /// ```
223 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
224 ///
225 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
226 /// assert_eq!(set.get_or_insert("abc"), &"abc");
227 /// assert_eq!(set.get_or_insert("def"), &"abc");
228 /// ```
229 pub fn get_or_insert<T>(&mut self, value: T) -> &T
230 where
231 T: ::core::any::Any $(+ $bounds)*,
232 {
233 use ::core::any::{Any, TypeId};
234 use ::alloc::boxed::Box;
235
236 #[cfg(debug_assertions)]
237 self.debug_type_names.insert(TypeId::of::<T>(), core::any::type_name::<T>());
238
239 let boxed_any: &Box<dyn Any $(+ $bounds)*> = self
240 .inner
241 .entry(TypeId::of::<T>())
242 .or_insert_with(|| Box::new(value));
243
244 // Sanity check
245 debug_assert!(boxed_any.as_ref().is::<T>());
246
247 let ptr = (boxed_any.as_ref() as *const dyn Any).cast::<T>();
248
249 unsafe { &*ptr }
250 }
251
252 /// Inserts a value computed from `f` into the set if it does not contain
253 /// a value of type `T`, then returns a reference to the value in the set.
254 ///
255 /// # Examples
256 ///
257 /// ```
258 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
259 ///
260 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
261 /// assert_eq!(set.get_or_insert_with(|| String::from("abc")), &"abc");
262 /// assert_eq!(set.get_or_insert_with(|| String::from("def")), &"abc");
263 /// ```
264 pub fn get_or_insert_with<T>(&mut self, f: impl FnOnce() -> T) -> &T
265 where
266 T: ::core::any::Any $(+ $bounds)*,
267 {
268 use ::core::any::{Any, TypeId};
269 use ::alloc::boxed::Box;
270
271 #[cfg(debug_assertions)]
272 self.debug_type_names.insert(TypeId::of::<T>(), core::any::type_name::<T>());
273
274 let boxed_any: &Box<dyn Any $(+ $bounds)*> = self
275 .inner
276 .entry(TypeId::of::<T>())
277 .or_insert_with(|| Box::new(f()));
278
279 // Sanity check
280 debug_assert!(boxed_any.as_ref().is::<T>());
281
282 let ptr = (boxed_any.as_ref() as *const dyn Any).cast::<T>();
283
284 unsafe { &*ptr }
285 }
286
287 /// Returns a mutable reference to an instance of `T`.
288 ///
289 /// If the set does not have an instance of `T`, [`None`] is returned.
290 ///
291 /// # Examples
292 ///
293 /// ```
294 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
295 ///
296 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
297 /// set.insert("a");
298 /// if let Some(x) = set.get_mut::<&str>() {
299 /// *x = "b";
300 /// }
301 /// assert_eq!(set.get::<&str>(), Some(&"b"));
302 /// ```
303 #[must_use]
304 pub fn get_mut<T>(&mut self) -> Option<&mut T>
305 where
306 T: ::core::any::Any $(+ $bounds)*,
307 {
308 use ::core::any::{Any, TypeId};
309 use ::alloc::boxed::Box;
310
311 self.inner
312 .get_mut(&TypeId::of::<T>())
313 .map(|boxed_any: &mut Box<dyn Any $(+ $bounds)*>| {
314 // Sanity check
315 debug_assert!(boxed_any.as_mut().is::<T>());
316
317 let ptr = (boxed_any.as_mut() as *mut dyn Any).cast::<T>();
318
319 unsafe { &mut *ptr }
320 })
321 }
322
323 /// Insert an instance of type `T` into the set.
324 ///
325 /// Returns the replaced value or [`None`].
326 ///
327 /// # Examples
328 ///
329 /// ```
330 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
331 ///
332 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
333 /// assert_eq!(set.insert("a"), None);
334 /// assert_eq!(set.insert("b"), Some("a"));
335 /// ```
336 pub fn insert<T>(&mut self, value: T) -> Option<T>
337 where
338 T: ::core::any::Any $(+ $bounds)*,
339 {
340 use ::core::any::{Any, TypeId};
341 use ::alloc::boxed::Box;
342
343 #[cfg(debug_assertions)]
344 self.debug_type_names.insert(TypeId::of::<T>(), core::any::type_name::<T>());
345
346 self.inner
347 .insert(TypeId::of::<T>(), Box::new(value))
348 .map(|boxed_any: Box<dyn Any $(+ $bounds)*>| {
349 // Sanity check
350 debug_assert!(boxed_any.as_ref().is::<T>());
351
352 let ptr = Box::into_raw(boxed_any).cast::<T>();
353
354 unsafe { *Box::from_raw(ptr) }
355 })
356 }
357
358 /// Remove and return an instance of type `T` from the set.
359 ///
360 /// If the set did not have this type present, [`None`] is returned.
361 ///
362 /// # Examples
363 ///
364 /// ```
365 #[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
366 ///
367 #[doc = concat!("let mut set = ", stringify!($name), "::new();")]
368 /// set.insert("a");
369 /// assert_eq!(set.remove::<&str>(), Some("a"));
370 /// ```
371 pub fn remove<T>(&mut self) -> Option<T>
372 where
373 T: ::core::any::Any $(+ $bounds)*,
374 {
375 use ::core::any::{Any, TypeId};
376 use ::alloc::boxed::Box;
377
378 #[cfg(debug_assertions)]
379 self.debug_type_names.remove(&TypeId::of::<T>());
380
381 self.inner
382 .remove(&TypeId::of::<T>())
383 .map(|boxed_any: Box<dyn Any $(+ $bounds)*>| {
384 // Sanity check
385 debug_assert!(boxed_any.as_ref().is::<T>());
386
387 let ptr = Box::into_raw(boxed_any).cast::<T>();
388
389 unsafe { *Box::from_raw(ptr) }
390 })
391 }
392
393 /// Gets an iterator over the [`TypeId`](::core::any::TypeId)s of stored elements, in arbitrary order.
394 pub fn type_ids(&self) -> impl Iterator<Item = &::core::any::TypeId> {
395 self.inner.keys()
396 }
397
398 /// Gets an iterator over the names of the stored types, in arbitrary order.
399 #[cfg(debug_assertions)]
400 pub fn debug_type_names(&self) -> impl Iterator<Item = &'static str> + '_ {
401 assert!(self.inner.keys().eq(self.debug_type_names.keys()));
402
403 self.debug_type_names.values().map(|&name: &&'static str| name)
404 }
405 }
406 }
407}
408
409impl_erased_set! {
410 /// A set of erased types.
411 ///
412 /// This set can store a single instance of any type that implements [`Any`](::core::any::Any).
413 ///
414 /// ## Example
415 ///
416 /// ```
417 /// # #[derive(Debug, PartialEq)]
418 /// # struct ClickEvent(u32, u32);
419 /// # #[derive(Debug, PartialEq)]
420 /// # struct KeyDownEvent(char);
421 /// #
422 /// use erased_set::ErasedSet;
423 ///
424 /// let mut set = ErasedSet::new();
425 /// set.insert(ClickEvent(128, 256));
426 /// set.insert(KeyDownEvent('z'));
427 ///
428 /// assert_eq!(set.get::<ClickEvent>(), Some(&ClickEvent(128, 256)));
429 ///
430 /// assert_eq!(set.insert(KeyDownEvent('e')), Some(KeyDownEvent('z')));
431 ///
432 /// set.remove::<ClickEvent>();
433 ///
434 /// assert_eq!(set.len(), 1);
435 /// ```
436 #[derive(Default)]
437 pub struct ErasedSet: Any;
438}
439
440impl core::fmt::Debug for ErasedSet {
441 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
442 f.debug_set()
443 .entries(
444 #[cfg(debug_assertions)]
445 self.debug_type_names(),
446 #[cfg(not(debug_assertions))]
447 self.type_ids(),
448 )
449 .finish()
450 }
451}
452
453#[cfg(feature = "send")]
454impl_erased_set! {
455 /// Like [`ErasedSet`] but with a [`Send`] bound.
456 ///
457 /// ## Example
458 ///
459 /// ```
460 /// # #[derive(Debug, PartialEq)]
461 /// # struct ClickEvent(u32, u32);
462 /// # #[derive(Debug, PartialEq)]
463 /// # struct KeyDownEvent(char);
464 /// #
465 /// use erased_set::ErasedSendSet;
466 ///
467 /// let mut set = ErasedSendSet::new();
468 /// set.insert(ClickEvent(128, 256));
469 /// set.insert(KeyDownEvent('z'));
470 ///
471 /// assert_eq!(set.get::<ClickEvent>(), Some(&ClickEvent(128, 256)));
472 ///
473 /// assert_eq!(set.insert(KeyDownEvent('e')), Some(KeyDownEvent('z')));
474 ///
475 /// set.remove::<ClickEvent>();
476 ///
477 /// assert_eq!(set.len(), 1);
478 /// ```
479 #[derive(Default)]
480 pub struct ErasedSendSet: Any + Send;
481}
482
483#[cfg(feature = "send")]
484impl core::fmt::Debug for ErasedSendSet {
485 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
486 f.debug_set()
487 .entries(
488 #[cfg(debug_assertions)]
489 self.debug_type_names(),
490 #[cfg(not(debug_assertions))]
491 self.type_ids(),
492 )
493 .finish()
494 }
495}
496
497#[cfg(feature = "sync")]
498impl_erased_set! {
499 /// Like [`ErasedSet`] but with a [`Send`] + [`Sync`] bound.
500 ///
501 /// ## Example
502 ///
503 /// ```
504 /// # #[derive(Debug, PartialEq)]
505 /// # struct ClickEvent(u32, u32);
506 /// # #[derive(Debug, PartialEq)]
507 /// # struct KeyDownEvent(char);
508 /// #
509 /// use erased_set::ErasedSyncSet;
510 ///
511 /// let mut set = ErasedSyncSet::new();
512 /// set.insert(ClickEvent(128, 256));
513 /// set.insert(KeyDownEvent('z'));
514 ///
515 /// assert_eq!(set.get::<ClickEvent>(), Some(&ClickEvent(128, 256)));
516 ///
517 /// assert_eq!(set.insert(KeyDownEvent('e')), Some(KeyDownEvent('z')));
518 ///
519 /// set.remove::<ClickEvent>();
520 ///
521 /// assert_eq!(set.len(), 1);
522 /// ```
523 #[derive(Default)]
524 pub struct ErasedSyncSet: Any + Send + Sync;
525}
526
527#[cfg(feature = "sync")]
528impl core::fmt::Debug for ErasedSyncSet {
529 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
530 f.debug_set()
531 .entries(
532 #[cfg(debug_assertions)]
533 self.debug_type_names(),
534 #[cfg(not(debug_assertions))]
535 self.type_ids(),
536 )
537 .finish()
538 }
539}