#![no_std]
extern crate alloc;
macro_rules! impl_erased_set {
(
$(#[$attr:meta])*
$vis:vis struct $name:ident: Any $(+ $bounds:tt)*;
) => {
$(#[$attr])*
$vis struct $name {
#[doc(hidden)]
inner: ::alloc::collections::BTreeMap<
::core::any::TypeId,
::alloc::boxed::Box<dyn ::core::any::Any $(+ $bounds)*>,
>,
#[doc(hidden)]
#[cfg(debug_assertions)]
debug_type_names: ::alloc::collections::BTreeMap<
::core::any::TypeId,
&'static str
>,
}
impl $name {
#[doc = concat!("Creates an empty [`", stringify!($name), "`].")]
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let set = ", stringify!($name), "::new();")]
#[must_use]
pub fn new() -> Self {
Self {
inner: ::alloc::collections::BTreeMap::new(),
#[cfg(debug_assertions)]
debug_type_names: ::alloc::collections::BTreeMap::new(),
}
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let set = ", stringify!($name), "::new();")]
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
#[must_use]
pub fn len(&self) -> usize {
self.inner.len()
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
pub fn clear(&mut self) {
self.inner.clear();
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
#[must_use]
pub fn contains<T>(&self) -> bool
where
T: ::core::any::Any,
{
self.inner.contains_key(&::core::any::TypeId::of::<T>())
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
#[must_use]
pub fn get<T>(&self) -> Option<&T>
where
T: ::core::any::Any $(+ $bounds)*,
{
use ::core::any::{Any, TypeId};
use ::alloc::boxed::Box;
self.inner
.get(&TypeId::of::<T>())
.map(|boxed_any: &Box<dyn Any $(+ $bounds)*>| {
debug_assert!(boxed_any.as_ref().is::<T>());
let ptr = (boxed_any.as_ref() as *const dyn Any).cast::<T>();
unsafe { &*ptr }
})
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
pub fn get_or_insert<T>(&mut self, value: T) -> &T
where
T: ::core::any::Any $(+ $bounds)*,
{
use ::core::any::{Any, TypeId};
use ::alloc::boxed::Box;
#[cfg(debug_assertions)]
self.debug_type_names.insert(TypeId::of::<T>(), core::any::type_name::<T>());
let boxed_any: &Box<dyn Any $(+ $bounds)*> = self
.inner
.entry(TypeId::of::<T>())
.or_insert_with(|| Box::new(value));
debug_assert!(boxed_any.as_ref().is::<T>());
let ptr = (boxed_any.as_ref() as *const dyn Any).cast::<T>();
unsafe { &*ptr }
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
pub fn get_or_insert_with<T>(&mut self, f: impl FnOnce() -> T) -> &T
where
T: ::core::any::Any $(+ $bounds)*,
{
use ::core::any::{Any, TypeId};
use ::alloc::boxed::Box;
#[cfg(debug_assertions)]
self.debug_type_names.insert(TypeId::of::<T>(), core::any::type_name::<T>());
let boxed_any: &Box<dyn Any $(+ $bounds)*> = self
.inner
.entry(TypeId::of::<T>())
.or_insert_with(|| Box::new(f()));
debug_assert!(boxed_any.as_ref().is::<T>());
let ptr = (boxed_any.as_ref() as *const dyn Any).cast::<T>();
unsafe { &*ptr }
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
#[must_use]
pub fn get_mut<T>(&mut self) -> Option<&mut T>
where
T: ::core::any::Any $(+ $bounds)*,
{
use ::core::any::{Any, TypeId};
use ::alloc::boxed::Box;
self.inner
.get_mut(&TypeId::of::<T>())
.map(|boxed_any: &mut Box<dyn Any $(+ $bounds)*>| {
debug_assert!(boxed_any.as_mut().is::<T>());
let ptr = (boxed_any.as_mut() as *mut dyn Any).cast::<T>();
unsafe { &mut *ptr }
})
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
pub fn insert<T>(&mut self, value: T) -> Option<T>
where
T: ::core::any::Any $(+ $bounds)*,
{
use ::core::any::{Any, TypeId};
use ::alloc::boxed::Box;
#[cfg(debug_assertions)]
self.debug_type_names.insert(TypeId::of::<T>(), core::any::type_name::<T>());
self.inner
.insert(TypeId::of::<T>(), Box::new(value))
.map(|boxed_any: Box<dyn Any $(+ $bounds)*>| {
debug_assert!(boxed_any.as_ref().is::<T>());
let ptr = Box::into_raw(boxed_any).cast::<T>();
unsafe { *Box::from_raw(ptr) }
})
}
#[doc = concat!("use ", module_path!(), "::", stringify!($name), ";")]
#[doc = concat!("let mut set = ", stringify!($name), "::new();")]
pub fn remove<T>(&mut self) -> Option<T>
where
T: ::core::any::Any $(+ $bounds)*,
{
use ::core::any::{Any, TypeId};
use ::alloc::boxed::Box;
#[cfg(debug_assertions)]
self.debug_type_names.remove(&TypeId::of::<T>());
self.inner
.remove(&TypeId::of::<T>())
.map(|boxed_any: Box<dyn Any $(+ $bounds)*>| {
debug_assert!(boxed_any.as_ref().is::<T>());
let ptr = Box::into_raw(boxed_any).cast::<T>();
unsafe { *Box::from_raw(ptr) }
})
}
pub fn type_ids(&self) -> impl Iterator<Item = &::core::any::TypeId> {
self.inner.keys()
}
#[cfg(debug_assertions)]
pub fn debug_type_names(&self) -> impl Iterator<Item = &'static str> + '_ {
assert!(self.inner.keys().eq(self.debug_type_names.keys()));
self.debug_type_names.values().map(|&name: &&'static str| name)
}
}
}
}
impl_erased_set! {
#[derive(Default)]
pub struct ErasedSet: Any;
}
impl core::fmt::Debug for ErasedSet {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_set()
.entries(
#[cfg(debug_assertions)]
self.debug_type_names(),
#[cfg(not(debug_assertions))]
self.type_ids(),
)
.finish()
}
}
#[cfg(feature = "send")]
impl_erased_set! {
#[derive(Default)]
pub struct ErasedSendSet: Any + Send;
}
#[cfg(feature = "send")]
impl core::fmt::Debug for ErasedSendSet {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_set()
.entries(
#[cfg(debug_assertions)]
self.debug_type_names(),
#[cfg(not(debug_assertions))]
self.type_ids(),
)
.finish()
}
}
#[cfg(feature = "sync")]
impl_erased_set! {
#[derive(Default)]
pub struct ErasedSyncSet: Any + Send + Sync;
}
#[cfg(feature = "sync")]
impl core::fmt::Debug for ErasedSyncSet {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_set()
.entries(
#[cfg(debug_assertions)]
self.debug_type_names(),
#[cfg(not(debug_assertions))]
self.type_ids(),
)
.finish()
}
}