use crate::Reflected;
use once_cell::sync::OnceCell;
use std::any::TypeId;
use std::collections::BTreeMap;
use std::sync::RwLock;
pub struct StaticTypeMap<T: 'static> {
map: RwLock<BTreeMap<TypeId, &'static OnceCell<T>>>,
}
impl<T: 'static> StaticTypeMap<T> {
pub const fn new() -> StaticTypeMap<T> {
StaticTypeMap {
map: RwLock::new(BTreeMap::new()),
}
}
pub fn call_once<Ty, F>(&'static self, f: F) -> &'static T
where
Ty: ?Sized + Reflected,
F: FnOnce() -> T,
{
let cell = {
let reader = self.map.read().unwrap();
reader.get(&TypeId::of::<Ty::Key>()).copied() };
if let Some(cell) = cell {
return cell.get_or_init(f);
}
let cell = {
let mut writer = self.map.write().unwrap();
let cell = writer.entry(TypeId::of::<Ty::Key>()).or_insert_with(|| {
let boxed = Box::new(OnceCell::new());
Box::leak(boxed)
});
*cell
};
cell.get_or_init(f)
}
}
impl<T: 'static> Default for StaticTypeMap<T> {
fn default() -> StaticTypeMap<T> {
StaticTypeMap::new()
}
}