use std::{ any::{Any, TypeId}, collections::HashMap, mem::transmute, }; #[derive(Default)] pub struct Resources { map: HashMap<TypeId, Box<dyn Any + Send + Sync>>, } impl Resources { pub fn insert<T: Any + Send + Sync>(&mut self, value: T) -> Option<T> { self.map .insert(TypeId::of::<T>(), Box::new(value)) .map(|any| *Self::downcast_unchecked(any)) } pub fn insert_if_not_exists<T: Default + Any + Send + Sync>(&mut self) { if !self.contains::<T>() { self.insert(T::default()); } } pub fn remove<T: Any + Send + Sync>(&mut self) -> Option<T> { self.map .remove(&TypeId::of::<T>()) .map(|any| *Self::downcast_unchecked(any)) } pub fn get<T: Any + Send + Sync>(&self) -> &T { self.map .get(&TypeId::of::<T>()) .map(|any| Self::downcast_ref_unchecked(any)) .unwrap() } pub fn get_mut<T: Any + Send + Sync>(&mut self) -> &mut T { self.map .get_mut(&TypeId::of::<T>()) .map(|any| Self::downcast_mut_unchecked(any)) .unwrap() } pub fn multi_mut(&mut self) -> ResourceMultiMut<'_> { ResourceMultiMut::new(&mut self.map) } pub fn contains<T: Any + Send + Sync>(&self) -> bool { self.map.contains_key(&TypeId::of::<T>()) } } // helper impl Resources { fn downcast_unchecked<T: Any + Send + Sync>(boxed: Box<dyn Any + Send + Sync>) -> Box<T> { unsafe { Box::from_raw(Box::into_raw(boxed) as *mut T) } } fn downcast_ref_unchecked<T: Any + Send + Sync>(boxed_ref: &Box<dyn Any + Send + Sync>) -> &T { unsafe { let ptr_to_ptr: *const *const T = transmute(destructure_traitobject::data(boxed_ref as *const _)); &**ptr_to_ptr } } fn downcast_mut_unchecked<T: Any + Send + Sync>( boxed_ref: &mut Box<dyn Any + Send + Sync>, ) -> &mut T { unsafe { let ptr_to_ptr: *mut *mut T = transmute(destructure_traitobject::data(boxed_ref as *mut _)); &mut **ptr_to_ptr } } } /// Allows mutable access to multiple components at once pub struct ResourceMultiMut<'a> { map: &'a mut HashMap<TypeId, Box<dyn Any + Send + Sync>>, buffer: Vec<*mut Box<dyn Any + Send + Sync>>, } impl<'a> ResourceMultiMut<'a> { fn new(map: &'a mut HashMap<TypeId, Box<dyn Any + Send + Sync>>) -> Self { ResourceMultiMut { map, buffer: Vec::new(), } } /// Returns requested type on success pub fn get<T: Any + Send + Sync>(&mut self) -> &'a mut T { self.get_by_type_id(&TypeId::of::<T>()) .map(|component| Resources::downcast_mut_unchecked(component)) .unwrap() } /// Returns requested type behind this type id on success pub fn get_by_type_id( &mut self, type_id: &TypeId, ) -> Option<&'a mut Box<dyn Any + Send + Sync>> { self.map.get_mut(type_id).map(|v| { let ptr = v as *mut _; match self.buffer.iter().find(|v| **v == ptr) { Some(_) => { panic!("This key has already been borrowed!"); } None => { self.buffer.push(ptr); } } let t: Option<&'a mut Box<dyn Any + Send + Sync>> = unsafe { transmute(ptr) }; t.unwrap() }) } /// # Safety /// /// use this only when there are no references left pub unsafe fn clear_all_usages(&mut self) { self.buffer.clear(); } }