use std::{any::{Any, TypeId}, sync::Arc}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use crate::{Tick, TickTracker}; /// Shorthand for `Send + Sync + 'static`, so it never needs to be implemented manually. pub trait ResourceObject: Send + Sync + Any { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; } impl ResourceObject for T { fn as_any(&self) -> &dyn Any { self } fn as_any_mut(&mut self) -> &mut dyn Any { self } } pub struct TrackedResource { pub tick: Tick, pub res: T, } /// A type erased storage for a Resource. #[derive(Clone)] pub struct ResourceData { pub(crate) data: Arc>>, type_id: TypeId, } impl ResourceData { pub fn new(data: T, tick: Tick) -> Self { Self { data: Arc::new(AtomicRefCell::new(TrackedResource { tick, res: data })), type_id: TypeId::of::(), } } /// Returns a boolean indicating whether or not `T`` is of the same type of the Resource pub fn is(&self) -> bool { self.type_id == TypeId::of::() } /// Borrow the data inside of the resource. /// /// # Panics /// /// * If the data is already borrowed mutably, this will panic. /// * If the type of `T` is not the same as the resource type. pub fn get(&self) -> AtomicRef { AtomicRef::map(self.data.borrow(), |a| a.res.as_any().downcast_ref().unwrap()) } /// Mutably borrow the data inside of the resource. /// /// # Panics /// /// * If the data is already borrowed mutably, this will panic. /// * If the type of `T` is not the same as the resource type. pub fn get_mut(&self) -> AtomicRefMut { AtomicRefMut::map(self.data.borrow_mut(), |a| a.res.as_any_mut().downcast_mut().unwrap()) } /// Borrow the data inside of the resource. /// /// # Panics /// /// * If the type of `T` is not the same as the resource type. pub fn try_get(&self) -> Option> { self.data.try_borrow() .map(|r| AtomicRef::map(r, |a| a.res.as_any().downcast_ref().unwrap())) .ok() } /// Mutably borrow the data inside of the resource. /// /// # Panics /// /// * If the type of `T` is not the same as the resource type. pub fn try_get_mut(&self) -> Option> { self.data.try_borrow_mut() .map(|r| AtomicRefMut::map(r, |a| a.res.as_any_mut().downcast_mut().unwrap())) .ok() } pub fn changed(&self, tick: Tick) -> bool { self.data.borrow().tick >= tick } }