use core::{hash::BuildHasherDefault, marker::PhantomData, mem, mem::ManuallyDrop, ptr};
use bumpalo::Bump;
use hashbrown::HashMap;
use rustc_hash::FxHasher;
use type_key::TypeKey;
#[derive(Debug)]
pub struct RawStore<'a> {
map: HashMap<TypeKey, ManuallyDealloc, BuildHasherDefault<FxHasher>>,
bump: ManuallyDrop<Bump>,
_phantom: PhantomData<&'a ()>,
}
impl<'a> RawStore<'a> {
pub fn new() -> Self {
Self {
map: HashMap::default(),
bump: ManuallyDrop::new(Bump::new()),
_phantom: PhantomData,
}
}
pub fn get<T: 'a>(&self, key: &TypeKey) -> Option<*const T> {
Some(self.map.get(key)?.ptr().cast::<T>())
}
pub fn insert<T: 'a>(&mut self, key: TypeKey, value: T) -> *const T {
let value =
unsafe { ManuallyDealloc(mem::transmute(self.bump.alloc(value) as &mut dyn Erased)) };
let ptr = value.ptr();
self.map.insert(key, value);
ptr.cast::<T>()
}
pub fn reset(&mut self) {
self.map.clear();
self.bump.reset();
}
}
impl Default for RawStore<'_> {
fn default() -> Self {
Self::new()
}
}
impl Drop for RawStore<'_> {
fn drop(&mut self) {
self.map.clear();
unsafe { ManuallyDrop::drop(&mut self.bump) }
}
}
trait Erased {}
impl<T> Erased for T {}
#[derive(Debug)]
#[repr(transparent)]
struct ManuallyDealloc(*mut dyn Erased);
impl ManuallyDealloc {
pub const fn ptr(&self) -> *const dyn Erased {
self.0.cast_const()
}
}
impl Drop for ManuallyDealloc {
fn drop(&mut self) {
unsafe { ptr::drop_in_place(self.0) }
}
}