use std::{
any::{Any, TypeId},
collections::HashMap,
hash::{BuildHasherDefault, Hasher},
sync::LazyLock,
};
use parking_lot::Mutex;
type AnyMap = HashMap<TypeId, Box<dyn StateClone + Send>, BuildHasherDefault<IdHasher>>;
static STATES: LazyLock<Mutex<AnyMap>> = LazyLock::new(|| Mutex::new(Default::default()));
#[derive(Default)]
struct IdHasher(u64);
impl Hasher for IdHasher {
fn write(&mut self, _: &[u8]) {
unreachable!("TypeId calls write_u64");
}
#[inline]
fn write_u64(&mut self, id: u64) {
self.0 = id;
}
#[inline]
fn finish(&self) -> u64 {
self.0
}
}
pub fn get<S>() -> S
where
S: StateClone + Clone + Send,
{
let type_id = TypeId::of::<S>();
match STATES.lock().get(&type_id) {
Some(state) => (**state).as_any().downcast_ref::<S>().unwrap().clone(),
None => panic!("State is missing from state registry"),
}
}
pub fn put<S>(state: S)
where
S: StateClone + Clone + Send,
{
let type_id = TypeId::of::<S>();
STATES.lock().insert(type_id, Box::new(state));
}
pub trait StateClone: Any {
fn clone_box(&self) -> Box<dyn StateClone + Send>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any>;
}
impl<T> StateClone for T
where
T: Clone + Send + 'static,
{
fn clone_box(&self) -> Box<dyn StateClone + Send> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl Clone for Box<dyn StateClone + Send + 'static> {
fn clone(&self) -> Self {
(**self).clone_box()
}
}