use parking_lot::{ MappedRwLockReadGuard, MappedRwLockWriteGuard, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, }; use std::sync::{Arc, OnceLock}; use crate::{ error::{self, ValueDroppedError}, references::{GenerationalRef, GenerationalRefMut}, AnyStorage, 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 { type Ref<'a, R: ?Sized + 'static> = GenerationalRef>; type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut>; fn downcast_lifetime_ref<'a: 'b, 'b, T: ?Sized + 'static>( ref_: Self::Ref<'a, T>, ) -> Self::Ref<'b, T> { ref_ } fn downcast_lifetime_mut<'a: 'b, 'b, T: ?Sized + 'static>( mut_: Self::Mut<'a, T>, ) -> Self::Mut<'b, T> { mut_ } fn try_map( ref_: Self::Ref<'_, I>, f: impl FnOnce(&I) -> Option<&U>, ) -> Option> { let GenerationalRef { inner, #[cfg(any(debug_assertions, feature = "debug_borrows"))] borrow, .. } = ref_; MappedRwLockReadGuard::try_map(inner, f) .ok() .map(|inner| GenerationalRef { inner, #[cfg(any(debug_assertions, feature = "debug_borrows"))] borrow: crate::GenerationalRefBorrowInfo { borrowed_at: borrow.borrowed_at, borrowed_from: borrow.borrowed_from, created_at: borrow.created_at, }, }) } fn try_map_mut( mut_ref: Self::Mut<'_, I>, f: impl FnOnce(&mut I) -> Option<&mut U>, ) -> Option> { let GenerationalRefMut { inner, #[cfg(any(debug_assertions, feature = "debug_borrows"))] borrow, .. } = mut_ref; MappedRwLockWriteGuard::try_map(inner, f) .ok() .map(|inner| GenerationalRefMut { inner, #[cfg(any(debug_assertions, feature = "debug_borrows"))] borrow: crate::GenerationalRefMutBorrowInfo { borrowed_from: borrow.borrowed_from, created_at: borrow.created_at, }, }) } fn data_ptr(&self) -> *const () { self.0.data_ptr() as *const () } fn manually_drop(&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 Storage for SyncStorage { fn try_read( &'static self, #[cfg(any(debug_assertions, feature = "debug_ownership"))] at: crate::GenerationalRefBorrowInfo, ) -> Result, error::BorrowError> { let read = self.0.try_read(); #[cfg(any(debug_assertions, feature = "debug_ownership"))] let read = read.ok_or_else(|| at.borrowed_from.borrow_error())?; #[cfg(not(any(debug_assertions, feature = "debug_ownership")))] let read = read.ok_or_else(|| { error::BorrowError::AlreadyBorrowedMut(error::AlreadyBorrowedMutError {}) })?; RwLockReadGuard::try_map(read, |any| any.as_ref()?.downcast_ref()) .map_err(|_| { error::BorrowError::Dropped(ValueDroppedError { #[cfg(any(debug_assertions, feature = "debug_ownership"))] created_at: at.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"))] at: crate::GenerationalRefMutBorrowInfo, ) -> Result, error::BorrowMutError> { let write = self.0.write(); RwLockWriteGuard::try_map(write, |any| any.as_mut()?.downcast_mut()) .map_err(|_| { error::BorrowMutError::Dropped(ValueDroppedError { #[cfg(any(debug_assertions, feature = "debug_ownership"))] created_at: at.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)); } fn take(&'static self) -> Option { self.0 .write() .take() .and_then(|any| any.downcast().ok().map(|boxed| *boxed)) } }