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}