use std::{ any::{Any, TypeId}, collections::HashMap, mem::transmute, }; #[derive(Default)] pub struct Resources { map: HashMap>, } impl Resources { pub fn insert(&mut self, value: T) -> Option { self.map .insert(TypeId::of::(), Box::new(value)) .map(|any| *Self::downcast_unchecked(any)) } pub fn insert_if_not_exists(&mut self) { if !self.contains::() { self.insert(T::default()); } } pub fn remove(&mut self) -> Option { self.map .remove(&TypeId::of::()) .map(|any| *Self::downcast_unchecked(any)) } pub fn get(&self) -> &T { self.get_opt::().unwrap() } pub fn get_opt(&self) -> Option<&T> { self.map .get(&TypeId::of::()) .map(|any| Self::downcast_ref_unchecked(any)) } pub fn get_mut(&mut self) -> &mut T { self.get_mut_opt::().unwrap() } pub fn get_mut_opt(&mut self) -> Option<&mut T> { self.map .get_mut(&TypeId::of::()) .map(|any| Self::downcast_mut_unchecked(any)) } pub fn multi_mut(&mut self) -> ResourceMultiMut<'_> { ResourceMultiMut::new(&mut self.map) } pub fn contains(&self) -> bool { self.map.contains_key(&TypeId::of::()) } } // helper impl Resources { fn downcast_unchecked(boxed: Box) -> Box { unsafe { Box::from_raw(Box::into_raw(boxed) as *mut T) } } fn downcast_ref_unchecked(boxed_ref: &Box) -> &T { unsafe { let ptr_to_ptr: *const *const T = transmute(destructure_traitobject::data(boxed_ref as *const _)); &**ptr_to_ptr } } fn downcast_mut_unchecked( boxed_ref: &mut Box, ) -> &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>, buffer: Vec<*mut Box>, } impl<'a> ResourceMultiMut<'a> { fn new(map: &'a mut HashMap>) -> Self { ResourceMultiMut { map, buffer: Vec::new(), } } /// Returns requested type on success pub fn get(&mut self) -> &'a mut T { self.get_by_type_id(&TypeId::of::()) .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> { 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> = 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(); } }