use super::Store;
use crate::utils::lock::{read_or_recover, write_or_recover};
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
struct TypeStoreCache {
stores: RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
}
impl TypeStoreCache {
fn new() -> Self {
Self {
stores: RwLock::new(HashMap::new()),
}
}
fn get_or_create<T>(&self, factory: impl FnOnce() -> T) -> Arc<T>
where
T: Store + 'static,
{
let type_id = TypeId::of::<T>();
{
let stores = read_or_recover(&self.stores);
if let Some(store_any) = stores.get(&type_id) {
if let Ok(store) = Arc::downcast::<T>(store_any.clone()) {
return store;
}
}
}
let new_store = Arc::new(factory());
let store_any: Arc<dyn Any + Send + Sync> = new_store.clone();
{
let mut stores = write_or_recover(&self.stores);
stores.insert(type_id, store_any);
}
new_store
}
}
fn type_store_cache() -> &'static TypeStoreCache {
use std::sync::OnceLock;
static CACHE: OnceLock<TypeStoreCache> = OnceLock::new();
CACHE.get_or_init(TypeStoreCache::new)
}
pub fn use_store<T>() -> Arc<T>
where
T: Store + Default + 'static,
{
type_store_cache().get_or_create::<T>(|| T::default())
}
pub fn create_store<T>() -> Arc<T>
where
T: Store + Default + 'static,
{
Arc::new(T::default())
}