use std::{any::{Any, TypeId}, collections::HashMap};
#[derive(Default, Debug)]
pub struct Resources {
values: HashMap<TypeId, Box<dyn Any>>
}
impl Resources {
pub fn new() -> Self {
Self::default()
}
pub fn add<T: Any>(&mut self, res: T) {
self.values.insert(TypeId::of::<T>(), Box::new(res));
}
pub fn get_ref<T: Any>(&self) -> eyre::Result<&T> {
let type_id = TypeId::of::<T>();
if let Some(data) = self.values.get(&type_id) {
data.downcast_ref().ok_or(ResourcesError::NonexistentResourceError.into())
} else {
Err(ResourcesError::NonexistentResourceError.into())
}
}
pub fn get_mut<T: Any>(&mut self) -> eyre::Result<&mut T> {
if let Some(data) = self.values.get_mut(&TypeId::of::<T>()) {
data.downcast_mut().ok_or(ResourcesError::NonexistentResourceError.into())
} else {
Err(ResourcesError::NonexistentResourceError.into())
}
}
pub fn delete<T: Any>(&mut self) -> eyre::Result<T> {
if let Some(data) = self.values.remove(&TypeId::of::<T>())
{
Ok(*data.downcast::<T>().unwrap())
} else {
Err(ResourcesError::NonexistentResourceError.into())
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum ResourcesError {
#[error("Attempt to access non existent resource.")]
NonexistentResourceError,
}
impl std::fmt::Display for Resources {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:#?}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_resource() {
let mut resources = Resources::new();
let thing = Thing(12);
resources.add(thing);
let retreived_thing = resources.values.get(&TypeId::of::<Thing>()).unwrap();
let thing2 = retreived_thing.downcast_ref::<Thing>().unwrap();
assert_eq!(thing2.0, 12);
}
#[test]
fn get_resource_mut() {
let mut resources = Resources::new();
let thing = Thing(12);
resources.add(thing);
{
let other = resources.get_mut::<Thing>().unwrap();
other.0 = 129;
}
let other = resources.get_ref::<Thing>().unwrap();
assert_eq!(other.0, 129);
}
#[test]
fn get_resource() {
let mut resources = Resources::new();
resources.add(Thing(12));
let thing = resources.get_ref::<Thing>().unwrap();
assert_eq!(thing.0, 12);
}
#[test]
fn delete_resource() -> eyre::Result<()> {
let mut resources = init_resources();
resources.delete::<Thing>()?;
assert!(resources.get_ref::<Thing>().is_err());
assert!(!resources.values.contains_key(&TypeId::of::<Thing>()));
Ok(())
}
fn init_resources() -> Resources {
let mut res = Resources::new();
res.add(Thing(10));
res
}
#[derive(Debug, PartialEq)]
struct Thing(i32);
}