use std::any::{Any, TypeId};
use rustc_hash::FxHashMap;
use std::collections::hash_map;
use std::marker::PhantomData;
pub struct KvPair(TypeId, Box<dyn Any>);
impl KvPair {
pub fn new<T: 'static>(value: T) -> Self {
KvPair(TypeId::of::<T>(), Box::new(value))
}
pub fn extract<T: 'static>(self) -> Result<T, Self> {
let KvPair(key, value) = self;
value.downcast().map(|boxed| *boxed).map_err(|e| KvPair(key, e))
}
}
#[derive(Debug)]
pub struct OccupiedEntry<'a, T> {
data: hash_map::OccupiedEntry<'a, TypeId, Box<dyn Any>>,
marker: PhantomData<fn(T)>,
}
impl<'a, T: 'static> OccupiedEntry<'a, T> {
pub fn get(&self) -> &T {
self.data.get().downcast_ref().unwrap()
}
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut().downcast_mut().unwrap()
}
pub fn into_mut(self) -> &'a mut T {
self.data.into_mut().downcast_mut().unwrap()
}
pub fn insert(&mut self, value: T) -> T {
self.data.insert(Box::new(value)).downcast().map(|boxed| *boxed).unwrap()
}
pub fn remove(self) -> T {
self.data.remove().downcast().map(|boxed| *boxed).unwrap()
}
}
#[derive(Debug)]
pub struct VacantEntry<'a, T> {
data: hash_map::VacantEntry<'a, TypeId, Box<dyn Any>>,
marker: PhantomData<fn(T)>,
}
impl<'a, T: 'static> VacantEntry<'a, T> {
pub fn insert(self, value: T) -> &'a mut T {
self.data.insert(Box::new(value)).downcast_mut().unwrap()
}
}
#[derive(Debug)]
pub enum Entry<'a, T> {
Occupied(OccupiedEntry<'a, T>),
Vacant(VacantEntry<'a, T>),
}
impl<'a, T: 'static> Entry<'a, T> {
pub fn or_insert(self, default: T) -> &'a mut T {
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default),
}
}
pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default()),
}
}
}
#[derive(Debug, Default)]
pub struct TypeMap {
map: Option<FxHashMap<TypeId, Box<dyn Any>>>,
}
impl TypeMap {
#[inline]
pub fn new() -> Self {
Self { map: None }
}
pub fn insert_kv_pair(&mut self, KvPair(key, value): KvPair) -> Option<KvPair> {
self.map
.get_or_insert_with(|| FxHashMap::default())
.insert(key, value)
.map(|old_value| KvPair(key, old_value))
}
pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> {
self.map
.get_or_insert_with(|| FxHashMap::default())
.insert(TypeId::of::<T>(), Box::new(val))
.and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed))
}
pub fn contains<T: 'static>(&self) -> bool {
self.map.as_ref().and_then(|m| m.get(&TypeId::of::<T>())).is_some()
}
pub fn get<T: 'static>(&self) -> Option<&T> {
self.map
.as_ref()
.and_then(|m| m.get(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast_ref())
}
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.map
.as_mut()
.and_then(|m| m.get_mut(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast_mut())
}
pub fn remove<T: 'static>(&mut self) -> Option<T> {
self.map
.as_mut()
.and_then(|m| m.remove(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed))
}
#[inline]
pub fn clear(&mut self) {
self.map = None;
}
pub fn entry<T: 'static>(&mut self) -> Entry<T> {
match self.map.get_or_insert_with(|| FxHashMap::default()).entry(TypeId::of::<T>()) {
hash_map::Entry::Occupied(e) => {
Entry::Occupied(OccupiedEntry { data: e, marker: PhantomData })
}
hash_map::Entry::Vacant(e) => {
Entry::Vacant(VacantEntry { data: e, marker: PhantomData })
}
}
}
}
pub mod concurrent {
use std::any::{Any, TypeId};
use rustc_hash::FxHashMap;
use std::collections::hash_map;
use std::marker::PhantomData;
pub struct KvPair(TypeId, Box<dyn Any + Send + Sync>);
impl KvPair {
pub fn new<T: 'static + Send + Sync>(value: T) -> Self {
KvPair(TypeId::of::<T>(), Box::new(value))
}
pub fn extract<T: 'static + Send + Sync>(self) -> Result<T, Self> {
let KvPair(key, value) = self;
if value.is::<T>() {
Ok((value as Box<dyn Any>).downcast().map(|boxed| *boxed).unwrap())
} else {
Err(KvPair(key, value))
}
}
}
#[derive(Debug)]
pub struct OccupiedEntry<'a, T> {
data: hash_map::OccupiedEntry<'a, TypeId, Box<dyn Any + Send + Sync>>,
marker: PhantomData<fn(T)>,
}
impl<'a, T: 'static + Send + Sync> OccupiedEntry<'a, T> {
pub fn get(&self) -> &T {
self.data.get().downcast_ref().unwrap()
}
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut().downcast_mut().unwrap()
}
pub fn into_mut(self) -> &'a mut T {
self.data.into_mut().downcast_mut().unwrap()
}
pub fn insert(&mut self, value: T) -> T {
(self.data.insert(Box::new(value)) as Box<dyn Any>)
.downcast()
.map(|boxed| *boxed)
.unwrap()
}
pub fn remove(self) -> T {
(self.data.remove() as Box<dyn Any>).downcast().map(|boxed| *boxed).unwrap()
}
}
#[derive(Debug)]
pub struct VacantEntry<'a, T> {
data: hash_map::VacantEntry<'a, TypeId, Box<dyn Any + Send + Sync>>,
marker: PhantomData<fn(T)>,
}
impl<'a, T: 'static + Send + Sync> VacantEntry<'a, T> {
pub fn insert(self, value: T) -> &'a mut T {
self.data.insert(Box::new(value)).downcast_mut().unwrap()
}
}
#[derive(Debug)]
pub enum Entry<'a, T> {
Occupied(OccupiedEntry<'a, T>),
Vacant(VacantEntry<'a, T>),
}
impl<'a, T: 'static + Send + Sync> Entry<'a, T> {
pub fn or_insert(self, default: T) -> &'a mut T {
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default),
}
}
pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
match self {
Entry::Occupied(inner) => inner.into_mut(),
Entry::Vacant(inner) => inner.insert(default()),
}
}
}
#[derive(Debug, Default)]
pub struct TypeMap {
map: Option<FxHashMap<TypeId, Box<dyn Any + Send + Sync>>>,
}
impl TypeMap {
#[inline]
pub fn new() -> Self {
Self { map: None }
}
pub fn insert_kv_pair(&mut self, KvPair(key, value): KvPair) -> Option<KvPair> {
self.map
.get_or_insert_with(|| FxHashMap::default())
.insert(key, value)
.map(|old_value| KvPair(key, old_value))
}
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
self.map
.get_or_insert_with(|| FxHashMap::default())
.insert(TypeId::of::<T>(), Box::new(val))
.and_then(|boxed| (boxed as Box<dyn Any>).downcast().ok().map(|boxed| *boxed))
}
pub fn contains<T: 'static>(&self) -> bool {
self.map.as_ref().and_then(|m| m.get(&TypeId::of::<T>())).is_some()
}
pub fn get<T: 'static>(&self) -> Option<&T> {
self.map
.as_ref()
.and_then(|m| m.get(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast_ref())
}
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.map
.as_mut()
.and_then(|m| m.get_mut(&TypeId::of::<T>()))
.and_then(|boxed| boxed.downcast_mut())
}
pub fn remove<T: 'static>(&mut self) -> Option<T> {
self.map
.as_mut()
.and_then(|m| m.remove(&TypeId::of::<T>()))
.and_then(|boxed| (boxed as Box<dyn Any>).downcast().ok().map(|boxed| *boxed))
}
#[inline]
pub fn clear(&mut self) {
self.map = None;
}
pub fn entry<T: 'static + Send + Sync>(&mut self) -> Entry<T> {
match self.map.get_or_insert_with(|| FxHashMap::default()).entry(TypeId::of::<T>()) {
hash_map::Entry::Occupied(e) => {
Entry::Occupied(OccupiedEntry { data: e, marker: PhantomData })
}
hash_map::Entry::Vacant(e) => {
Entry::Vacant(VacantEntry { data: e, marker: PhantomData })
}
}
}
}
}
#[test]
fn test_type_map() {
#[derive(Debug, PartialEq)]
struct MyType(i32);
#[derive(Debug, PartialEq, Default)]
struct MyType2(String);
let mut map = TypeMap::new();
map.insert(5i32);
map.insert(MyType(10));
assert_eq!(map.get(), Some(&5i32));
assert_eq!(map.get_mut(), Some(&mut 5i32));
assert_eq!(map.remove::<i32>(), Some(5i32));
assert!(map.get::<i32>().is_none());
assert_eq!(map.get::<bool>(), None);
assert_eq!(map.get(), Some(&MyType(10)));
let entry = map.entry::<MyType2>();
let mut v = entry.or_insert_with(MyType2::default);
v.0 = "Hello".into();
assert_eq!(map.get(), Some(&MyType2("Hello".into())));
}