#![allow(dead_code)]
use std::collections::hash_map;
use std::marker::PhantomData;
use std::{
any::{Any, TypeId},
collections::HashMap,
fmt::{self, Debug},
};
pub struct AnyAttribute(TypeId, Box<dyn Bucket>, Box<dyn Any>);
impl std::fmt::Debug for AnyAttribute {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AnyAttribute").finish()
}
}
impl AnyAttribute {
pub fn new<T: 'static + Debug>(value: T) -> Self {
AnyAttribute(
TypeId::of::<T>(),
Box::new(Vec::<T>::new()),
Box::new(value),
)
}
pub fn extract<T: 'static>(self) -> Result<T, Self> {
let AnyAttribute(key, empty_bucket, value) = self;
value
.downcast()
.map(|boxed| *boxed)
.map_err(|e| AnyAttribute(key, empty_bucket, e))
}
pub fn type_id(&self) -> TypeId {
self.0
}
}
#[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 TypeBucket {
map: HashMap<TypeId, Box<dyn Bucket>>,
}
impl fmt::Debug for dyn Bucket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Bucket::debug(self, f)
}
}
trait Bucket {
fn as_any(&self) -> &dyn Any
where
Self: 'static;
fn as_any_mut(&mut self) -> &mut dyn Any
where
Self: 'static;
fn insert_any(&mut self, val: Box<dyn Any>);
fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("Bucket")
}
fn default() -> Self
where
Self: Sized + Default,
{
Default::default()
}
}
impl<T: 'static + Debug> Bucket for Vec<T> {
#[inline]
fn as_any(&self) -> &dyn Any {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn insert_any(&mut self, val: Box<dyn Any>) {
self.push(*val.downcast().expect("type doesn't match"));
}
fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(self, f)
}
}
impl TypeBucket {
#[inline]
pub fn new() -> Self {
Self {
map: Default::default(),
}
}
pub fn insert_any_attribute(&mut self, AnyAttribute(key, empty_value, value): AnyAttribute) {
self.map.entry(key).or_insert(empty_value).insert_any(value)
}
#[track_caller]
pub fn insert<T: 'static + Debug>(&mut self, val: T) {
self.map
.entry(TypeId::of::<T>())
.or_insert_with(|| Box::new(Vec::<T>::new()))
.as_any_mut()
.downcast_mut::<Vec<T>>()
.unwrap()
.push(val);
}
pub fn get<T: 'static>(&self) -> &[T] {
self.map
.get(&TypeId::of::<T>())
.map(|boxed_vec| boxed_vec.as_any().downcast_ref::<Vec<T>>().unwrap())
.map(|vec| vec.as_slice())
.unwrap_or_else(|| &[])
}
pub fn get_debug<T: 'static + Debug>(&self) -> Vec<String> {
self.map
.get(&TypeId::of::<T>())
.map(|vec| {
vec.as_any()
.downcast_ref::<Vec<T>>()
.unwrap()
.iter()
.map(|item| format!("{:?}", item))
.collect()
})
.unwrap_or_default()
}
#[inline]
pub fn clear(&mut self) {
self.map = Default::default();
}
}
#[test]
fn test_type_map() {
#[derive(Debug, PartialEq)]
struct MyType(i32);
#[derive(Debug, PartialEq, Default)]
struct MyType2(String);
let mut map = TypeBucket::new();
map.insert(5i32);
map.insert(MyType(10));
assert_eq!(map.get::<i32>(), &[5i32]);
assert_eq!(map.get::<bool>(), &[] as &[bool]);
assert_eq!(map.get::<MyType>(), &[MyType(10)]);
map.insert(MyType(20));
assert_eq!(map.get::<MyType>(), &[MyType(10), MyType(20)]);
}