use crate::{ references::{GenerationalRef, GenerationalRefMut}, AnyStorage, Mappable, MappableMut, MemoryLocation, MemoryLocationInner, Storage, }; use std::cell::{Ref, RefCell, RefMut}; /// A unsync storage. This is the default storage type. pub struct UnsyncStorage(RefCell>>); impl Default for UnsyncStorage { fn default() -> Self { Self(RefCell::new(None)) } } impl Mappable for Ref<'static, T> { type Mapped = Ref<'static, U>; fn map(_self: Self, f: impl FnOnce(&T) -> &U) -> Self::Mapped { Ref::map(_self, f) } fn try_map( _self: Self, f: impl FnOnce(&T) -> Option<&U>, ) -> Option> { Ref::filter_map(_self, f).ok() } } impl MappableMut for RefMut<'static, T> { type Mapped = RefMut<'static, U>; fn map(_self: Self, f: impl FnOnce(&mut T) -> &mut U) -> Self::Mapped { RefMut::map(_self, f) } fn try_map( _self: Self, f: impl FnOnce(&mut T) -> Option<&mut U>, ) -> Option> { RefMut::filter_map(_self, f).ok() } } impl Storage for UnsyncStorage { type Ref = GenerationalRef>; type Mut = GenerationalRefMut>; fn try_read( &'static self, #[cfg(any(debug_assertions, feature = "debug_ownership"))] created_at: &'static std::panic::Location<'static>, #[cfg(any(debug_assertions, feature = "debug_ownership"))] at: crate::GenerationalRefBorrowInfo, ) -> Result { let borrow = self .0 .try_borrow() .map_err(|_| at.borrowed_from.borrow_error())?; Ref::filter_map(borrow, |any| any.as_ref()?.downcast_ref()) .map_err(|_| { crate::error::BorrowError::Dropped(crate::error::ValueDroppedError { #[cfg(any(debug_assertions, feature = "debug_ownership"))] created_at, }) }) .map(|guard| { GenerationalRef::new( guard, #[cfg(any(debug_assertions, feature = "debug_ownership"))] at, ) }) } fn try_write( &'static self, #[cfg(any(debug_assertions, feature = "debug_ownership"))] created_at: &'static std::panic::Location<'static>, #[cfg(any(debug_assertions, feature = "debug_ownership"))] at: crate::GenerationalRefMutBorrowInfo, ) -> Result { let borrow = self .0 .try_borrow_mut() .map_err(|_| at.borrowed_from.borrow_mut_error())?; RefMut::filter_map(borrow, |any| any.as_mut()?.downcast_mut()) .map_err(|_| { crate::error::BorrowMutError::Dropped(crate::error::ValueDroppedError { #[cfg(any(debug_assertions, feature = "debug_ownership"))] created_at, }) }) .map(|guard| { GenerationalRefMut::new( guard, #[cfg(any(debug_assertions, feature = "debug_ownership"))] at, ) }) } fn set(&self, value: T) { *self.0.borrow_mut() = Some(Box::new(value)); } } thread_local! { static UNSYNC_RUNTIME: RefCell>> = RefCell::new(Vec::new()); } impl AnyStorage for UnsyncStorage { fn data_ptr(&self) -> *const () { self.0.as_ptr() as *const () } fn take(&self) -> bool { self.0.borrow_mut().take().is_some() } fn claim() -> MemoryLocation { UNSYNC_RUNTIME.with(|runtime| { if let Some(location) = runtime.borrow_mut().pop() { location } else { let data: &'static MemoryLocationInner = &*Box::leak(Box::new(MemoryLocationInner { data: Self::default(), #[cfg(any(debug_assertions, feature = "check_generation"))] generation: 0.into(), #[cfg(any(debug_assertions, feature = "debug_borrows"))] borrow: Default::default(), })); MemoryLocation(data) } }) } fn recycle(location: &MemoryLocation) { location.drop(); UNSYNC_RUNTIME.with(|runtime| runtime.borrow_mut().push(*location)); } }