use parking_lot::{ MappedRwLockReadGuard, MappedRwLockWriteGuard, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, }; use std::sync::{Arc, OnceLock}; use crate::{ error::{self, ValueDroppedError}, references::{ GenerationalRef, GenerationalRefBorrowInfo, GenerationalRefMut, GenerationalRefMutBorrowInfo, }, AnyStorage, Mappable, MappableMut, MemoryLocation, MemoryLocationInner, Storage, }; /// A thread safe storage. This is slower than the unsync storage, but allows you to share the value between threads. #[derive(Default)] pub struct SyncStorage(RwLock>>); static SYNC_RUNTIME: OnceLock>>>> = OnceLock::new(); fn sync_runtime() -> &'static Arc>>> { SYNC_RUNTIME.get_or_init(|| Arc::new(Mutex::new(Vec::new()))) } impl AnyStorage for SyncStorage { fn data_ptr(&self) -> *const () { self.0.data_ptr() as *const () } fn take(&self) -> bool { self.0.write().take().is_some() } fn claim() -> MemoryLocation { sync_runtime().lock().pop().unwrap_or_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(); sync_runtime().lock().push(*location); } } impl Mappable for MappedRwLockReadGuard<'static, T> { type Mapped = MappedRwLockReadGuard<'static, U>; fn map(_self: Self, f: impl FnOnce(&T) -> &U) -> Self::Mapped { MappedRwLockReadGuard::map(_self, f) } fn try_map( _self: Self, f: impl FnOnce(&T) -> Option<&U>, ) -> Option> { MappedRwLockReadGuard::try_map(_self, f).ok() } } impl MappableMut for MappedRwLockWriteGuard<'static, T> { type Mapped = MappedRwLockWriteGuard<'static, U>; fn map(_self: Self, f: impl FnOnce(&mut T) -> &mut U) -> Self::Mapped { MappedRwLockWriteGuard::map(_self, f) } fn try_map( _self: Self, f: impl FnOnce(&mut T) -> Option<&mut U>, ) -> Option> { MappedRwLockWriteGuard::try_map(_self, f).ok() } } impl Storage for SyncStorage { 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: GenerationalRefBorrowInfo, ) -> Result { RwLockReadGuard::try_map(self.0.read(), |any| any.as_ref()?.downcast_ref()) .map_err(|_| { error::BorrowError::Dropped(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: GenerationalRefMutBorrowInfo, ) -> Result { RwLockWriteGuard::try_map(self.0.write(), |any| any.as_mut()?.downcast_mut()) .map_err(|_| { error::BorrowMutError::Dropped(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.write() = Some(Box::new(value)); } }