#[expect(clippy::disallowed_types)]
use std::{
any::{Any, TypeId, type_name},
collections::HashMap,
sync::Arc,
};
use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
#[derive(Default, Clone)]
#[expect(clippy::disallowed_types)]
pub struct Resources(Arc<RwLock<HashMap<TypeId, Box<dyn Any + Send + Sync>>>>);
impl Resources {
pub fn put<T: Any + Send + Sync>(&self, resource: T) {
self.0.write().insert(TypeId::of::<T>(), Box::new(resource));
}
pub fn get<T: Any + Send + Sync>(&self) -> anyhow::Result<MappedRwLockReadGuard<'_, T>> {
RwLockReadGuard::try_map(self.0.read(), |res| res.get(&TypeId::of::<T>())?.downcast_ref::<T>())
.map_err(|_| anyhow::anyhow!("Resource of type `{}` not found", type_name::<T>()))
}
pub fn get_mut<T: Any + Send + Sync>(&self) -> anyhow::Result<MappedRwLockWriteGuard<'_, T>> {
RwLockWriteGuard::try_map(self.0.write(), |res| res.get_mut(&TypeId::of::<T>())?.downcast_mut::<T>())
.map_err(|_| anyhow::anyhow!("Resource of type `{}` not found", type_name::<T>()))
}
pub fn take<T: Any + Send + Sync>(&self) -> anyhow::Result<T> {
self.0
.write()
.remove(&TypeId::of::<T>())
.ok_or_else(|| anyhow::anyhow!("Resource of type `{}` not found", type_name::<T>()))?
.downcast::<T>()
.map(|x| *x)
.map_err(|_| anyhow::anyhow!("Resource of type `{}` not found", type_name::<T>()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resources() {
let resources = Resources::default();
assert_eq!(resources.get::<u32>().unwrap_err().to_string(), "Resource of type `u32` not found");
resources.put(42u32);
assert_eq!(*resources.get::<u32>().unwrap(), 42);
resources.put(43u32);
assert_eq!(*resources.get_mut::<u32>().unwrap(), 43);
assert_eq!(resources.take::<u32>().unwrap(), 43);
assert_eq!(resources.take::<u32>().unwrap_err().to_string(), "Resource of type `u32` not found");
}
}