use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt;
use std::hash::BuildHasherDefault;
use crate::boxed::AnyCloneBox;
use crate::utils::IdHasher;
#[repr(transparent)]
#[derive(Clone)]
pub struct AnyMap {
map: HashMap<TypeId, AnyCloneBox, BuildHasherDefault<IdHasher>>,
}
impl Default for AnyMap {
fn default() -> Self {
Self::new()
}
}
impl AnyMap {
pub fn new() -> AnyMap {
AnyMap {
map: HashMap::default(),
}
}
pub fn with_capacity(capacity: usize) -> AnyMap {
AnyMap {
map: HashMap::with_capacity_and_hasher(
capacity,
BuildHasherDefault::<IdHasher>::default(),
),
}
}
pub fn capacity(&self) -> usize {
self.map.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.map.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.map.shrink_to_fit();
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn clear(&mut self) {
self.map.clear();
}
pub fn get<T: Any>(&self) -> Option<&T> {
self.map.get(&TypeId::of::<T>()).map(|elem| unsafe {
debug_assert_eq!(
AnyCloneBox::type_id(elem),
TypeId::of::<T>(),
"TypeId mismatch in AnyMap::get. This should never happen!"
);
elem.downcast_ref_unchecked()
})
}
pub fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
self.map.get_mut(&TypeId::of::<T>()).map(|elem| unsafe {
debug_assert_eq!(
AnyCloneBox::type_id(elem),
TypeId::of::<T>(),
"TypeId mismatch in AnyMap::get_mut. This should never happen!"
);
elem.downcast_mut_unchecked()
})
}
pub fn insert<T: Any + Clone + Send + Sync>(&mut self, value: T) -> Option<T> {
self.map
.insert(TypeId::of::<T>(), AnyCloneBox::new(value))
.map(|old_value| unsafe {
debug_assert_eq!(
AnyCloneBox::type_id(&old_value),
TypeId::of::<T>(),
"TypeId mismatch in AnyMap::insert. This should never happen!"
);
*old_value.downcast_unchecked()
})
}
pub fn insert_boxed(&mut self, value: AnyCloneBox) -> Option<AnyCloneBox> {
self.map.insert(value.type_id(), value)
}
pub fn try_insert<T: Any + Clone + Send + Sync>(&mut self, value: T) -> Result<(), T> {
match self.map.entry(TypeId::of::<T>()) {
Entry::Occupied(_) => Err(value),
Entry::Vacant(entry) => {
entry.insert(AnyCloneBox::new(value));
Ok(())
}
}
}
pub fn try_insert_boxed(&mut self, value: AnyCloneBox) -> Result<(), AnyCloneBox> {
match self.map.entry(value.type_id()) {
Entry::Occupied(_) => Err(value),
Entry::Vacant(entry) => {
entry.insert(value);
Ok(())
}
}
}
pub fn remove<T: Any>(&mut self) -> Option<T> {
self.map.remove(&TypeId::of::<T>()).map(|old_value| unsafe {
debug_assert_eq!(
AnyCloneBox::type_id(&old_value),
TypeId::of::<T>(),
"TypeId mismatch in AnyMap::remove. This should never happen!"
);
*old_value.downcast_unchecked()
})
}
pub fn contains<T: Any>(&self) -> bool {
self.map.contains_key(&TypeId::of::<T>())
}
}
impl fmt::Debug for AnyMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set()
.entries(self.map.values().map(|any_clone| any_clone.type_name()))
.finish()
}
}