2024-08-23 11:22:09 +00:00
|
|
|
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 {
|
2025-02-26 13:51:44 +00:00
|
|
|
self.get_opt::<T>().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_opt<T: Any + Send + Sync>(&self) -> Option<&T> {
|
2024-08-23 11:22:09 +00:00
|
|
|
self.map
|
|
|
|
.get(&TypeId::of::<T>())
|
|
|
|
.map(|any| Self::downcast_ref_unchecked(any))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_mut<T: Any + Send + Sync>(&mut self) -> &mut T {
|
2025-02-26 13:51:44 +00:00
|
|
|
self.get_mut_opt::<T>().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_mut_opt<T: Any + Send + Sync>(&mut self) -> Option<&mut T> {
|
2024-08-23 11:22:09 +00:00
|
|
|
self.map
|
|
|
|
.get_mut(&TypeId::of::<T>())
|
|
|
|
.map(|any| Self::downcast_mut_unchecked(any))
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|