123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- use parking_lot::{
- MappedRwLockReadGuard, MappedRwLockWriteGuard, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard,
- };
- use std::{
- any::Any,
- fmt::Debug,
- num::NonZeroU64,
- sync::{Arc, OnceLock},
- };
- use crate::{
- entry::{MemoryLocationBorrowInfo, RcStorageEntry, StorageEntry},
- error::{self, ValueDroppedError},
- references::{GenerationalRef, GenerationalRefMut},
- AnyStorage, BorrowError, BorrowMutError, BorrowMutResult, BorrowResult, GenerationalLocation,
- GenerationalPointer, Storage,
- };
- type RwLockStorageEntryRef = RwLockReadGuard<'static, StorageEntry<RwLockStorageEntryData>>;
- type RwLockStorageEntryMut = RwLockWriteGuard<'static, StorageEntry<RwLockStorageEntryData>>;
- pub(crate) enum RwLockStorageEntryData {
- Reference(GenerationalPointer<SyncStorage>),
- Rc(RcStorageEntry<Box<dyn Any + Send + Sync>>),
- Data(Box<dyn Any + Send + Sync>),
- Empty,
- }
- impl Default for RwLockStorageEntryData {
- fn default() -> Self {
- Self::Empty
- }
- }
- impl Debug for RwLockStorageEntryData {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Self::Reference(location) => write!(f, "Reference({:?})", location),
- Self::Rc(_) => write!(f, "Rc"),
- Self::Data(_) => write!(f, "Data"),
- Self::Empty => write!(f, "Empty"),
- }
- }
- }
- impl RwLockStorageEntryData {
- pub const fn new_full(data: Box<dyn Any + Send + Sync>) -> Self {
- Self::Data(data)
- }
- }
- /// 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 {
- borrow_info: MemoryLocationBorrowInfo,
- data: RwLock<StorageEntry<RwLockStorageEntryData>>,
- }
- impl SyncStorage {
- pub(crate) fn read(
- pointer: GenerationalPointer<Self>,
- ) -> BorrowResult<MappedRwLockReadGuard<'static, Box<dyn Any + Send + Sync + 'static>>> {
- Self::get_split_ref(pointer).map(|(_, guard)| {
- RwLockReadGuard::map(guard, |data| match &data.data {
- RwLockStorageEntryData::Data(data) => data,
- RwLockStorageEntryData::Rc(data) => &data.data,
- _ => unreachable!(),
- })
- })
- }
- pub(crate) fn get_split_ref(
- mut pointer: GenerationalPointer<Self>,
- ) -> BorrowResult<(GenerationalPointer<Self>, RwLockStorageEntryRef)> {
- loop {
- let borrow = pointer.storage.data.read();
- if !borrow.valid(&pointer.location) {
- return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
- pointer.location,
- )));
- }
- match &borrow.data {
- // If this is a reference, keep traversing the pointers
- RwLockStorageEntryData::Reference(data) => {
- pointer = *data;
- }
- // Otherwise return the value
- RwLockStorageEntryData::Data(_) | RwLockStorageEntryData::Rc(_) => {
- return Ok((pointer, borrow));
- }
- RwLockStorageEntryData::Empty => {
- return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
- pointer.location,
- )));
- }
- }
- }
- }
- pub(crate) fn write(
- pointer: GenerationalPointer<Self>,
- ) -> BorrowMutResult<MappedRwLockWriteGuard<'static, Box<dyn Any + Send + Sync + 'static>>>
- {
- Self::get_split_mut(pointer).map(|(_, guard)| {
- RwLockWriteGuard::map(guard, |data| match &mut data.data {
- RwLockStorageEntryData::Data(data) => data,
- RwLockStorageEntryData::Rc(data) => &mut data.data,
- _ => unreachable!(),
- })
- })
- }
- pub(crate) fn get_split_mut(
- mut pointer: GenerationalPointer<Self>,
- ) -> BorrowMutResult<(GenerationalPointer<Self>, RwLockStorageEntryMut)> {
- loop {
- let borrow = pointer.storage.data.write();
- if !borrow.valid(&pointer.location) {
- return Err(BorrowMutError::Dropped(
- ValueDroppedError::new_for_location(pointer.location),
- ));
- }
- match &borrow.data {
- // If this is a reference, keep traversing the pointers
- RwLockStorageEntryData::Reference(data) => {
- pointer = *data;
- }
- // Otherwise return the value
- RwLockStorageEntryData::Data(_) | RwLockStorageEntryData::Rc(_) => {
- return Ok((pointer, borrow));
- }
- RwLockStorageEntryData::Empty => {
- return Err(BorrowMutError::Dropped(
- ValueDroppedError::new_for_location(pointer.location),
- ));
- }
- }
- }
- }
- fn create_new(
- value: RwLockStorageEntryData,
- #[allow(unused)] caller: &'static std::panic::Location<'static>,
- ) -> GenerationalPointer<Self> {
- match sync_runtime().lock().pop() {
- Some(storage) => {
- let mut write = storage.data.write();
- let location = GenerationalLocation {
- generation: write.generation(),
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
- created_at: caller,
- };
- write.data = value;
- GenerationalPointer { storage, location }
- }
- None => {
- let storage: &'static Self = &*Box::leak(Box::new(Self {
- borrow_info: Default::default(),
- data: RwLock::new(StorageEntry::new(value)),
- }));
- let location = GenerationalLocation {
- generation: NonZeroU64::MIN,
- #[cfg(any(debug_assertions, feature = "debug_borrows"))]
- created_at: caller,
- };
- GenerationalPointer { storage, location }
- }
- }
- }
- }
- static SYNC_RUNTIME: OnceLock<Arc<Mutex<Vec<&'static SyncStorage>>>> = OnceLock::new();
- fn sync_runtime() -> &'static Arc<Mutex<Vec<&'static SyncStorage>>> {
- SYNC_RUNTIME.get_or_init(|| Arc::new(Mutex::new(Vec::new())))
- }
- impl AnyStorage for SyncStorage {
- type Ref<'a, R: ?Sized + 'static> = GenerationalRef<MappedRwLockReadGuard<'a, R>>;
- type Mut<'a, W: ?Sized + 'static> = GenerationalRefMut<MappedRwLockWriteGuard<'a, W>>;
- 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 map<T: ?Sized + 'static, U: ?Sized + 'static>(
- ref_: Self::Ref<'_, T>,
- f: impl FnOnce(&T) -> &U,
- ) -> Self::Ref<'_, U> {
- ref_.map(|inner| MappedRwLockReadGuard::map(inner, f))
- }
- fn map_mut<T: ?Sized + 'static, U: ?Sized + 'static>(
- mut_ref: Self::Mut<'_, T>,
- f: impl FnOnce(&mut T) -> &mut U,
- ) -> Self::Mut<'_, U> {
- mut_ref.map(|inner| MappedRwLockWriteGuard::map(inner, f))
- }
- fn try_map<I: ?Sized + 'static, U: ?Sized + 'static>(
- ref_: Self::Ref<'_, I>,
- f: impl FnOnce(&I) -> Option<&U>,
- ) -> Option<Self::Ref<'_, U>> {
- ref_.try_map(|inner| MappedRwLockReadGuard::try_map(inner, f).ok())
- }
- fn try_map_mut<I: ?Sized + 'static, U: ?Sized + 'static>(
- mut_ref: Self::Mut<'_, I>,
- f: impl FnOnce(&mut I) -> Option<&mut U>,
- ) -> Option<Self::Mut<'_, U>> {
- mut_ref.try_map(|inner| MappedRwLockWriteGuard::try_map(inner, f).ok())
- }
- fn data_ptr(&self) -> *const () {
- self.data.data_ptr() as *const ()
- }
- fn recycle(pointer: GenerationalPointer<Self>) {
- let mut borrow_mut = pointer.storage.data.write();
- // First check if the generation is still valid
- if !borrow_mut.valid(&pointer.location) {
- return;
- }
- borrow_mut.increment_generation();
- // Then decrement the reference count or drop the value if it's the last reference
- match &mut borrow_mut.data {
- // If this is the original reference, drop the value
- RwLockStorageEntryData::Data(_) => borrow_mut.data = RwLockStorageEntryData::Empty,
- // If this is a rc, just ignore the drop
- RwLockStorageEntryData::Rc(_) => {}
- // If this is a reference, decrement the reference count
- RwLockStorageEntryData::Reference(reference) => {
- drop_ref(*reference);
- }
- RwLockStorageEntryData::Empty => {}
- }
- sync_runtime().lock().push(pointer.storage);
- }
- }
- fn drop_ref(pointer: GenerationalPointer<SyncStorage>) {
- let mut borrow_mut = pointer.storage.data.write();
- // First check if the generation is still valid
- if !borrow_mut.valid(&pointer.location) {
- return;
- }
- if let RwLockStorageEntryData::Rc(entry) = &mut borrow_mut.data {
- // Decrement the reference count
- if entry.drop_ref() {
- // If the reference count is now zero, drop the value
- borrow_mut.data = RwLockStorageEntryData::Empty;
- sync_runtime().lock().push(pointer.storage);
- }
- } else {
- unreachable!("References should always point to a data entry directly");
- }
- }
- impl<T: Sync + Send + 'static> Storage<T> for SyncStorage {
- #[track_caller]
- fn try_read(
- pointer: GenerationalPointer<Self>,
- ) -> Result<Self::Ref<'static, T>, error::BorrowError> {
- let read = Self::read(pointer)?;
- let read = MappedRwLockReadGuard::try_map(read, |any| {
- // Then try to downcast
- any.downcast_ref()
- });
- match read {
- Ok(guard) => Ok(GenerationalRef::new(
- guard,
- pointer.storage.borrow_info.borrow_guard(),
- )),
- Err(_) => Err(error::BorrowError::Dropped(
- ValueDroppedError::new_for_location(pointer.location),
- )),
- }
- }
- #[track_caller]
- fn try_write(
- pointer: GenerationalPointer<Self>,
- ) -> Result<Self::Mut<'static, T>, error::BorrowMutError> {
- let write = Self::write(pointer)?;
- let write = MappedRwLockWriteGuard::try_map(write, |any| {
- // Then try to downcast
- any.downcast_mut()
- });
- match write {
- Ok(guard) => Ok(GenerationalRefMut::new(
- guard,
- pointer.storage.borrow_info.borrow_mut_guard(),
- )),
- Err(_) => Err(error::BorrowMutError::Dropped(
- ValueDroppedError::new_for_location(pointer.location),
- )),
- }
- }
- fn new(value: T, caller: &'static std::panic::Location<'static>) -> GenerationalPointer<Self> {
- Self::create_new(RwLockStorageEntryData::new_full(Box::new(value)), caller)
- }
- fn new_rc(
- value: T,
- caller: &'static std::panic::Location<'static>,
- ) -> GenerationalPointer<Self> {
- // Create the data that the rc points to
- let data = Self::create_new(
- RwLockStorageEntryData::Rc(RcStorageEntry::new(Box::new(value))),
- caller,
- );
- Self::create_new(RwLockStorageEntryData::Reference(data), caller)
- }
- fn new_reference(
- location: GenerationalPointer<Self>,
- ) -> BorrowResult<GenerationalPointer<Self>> {
- // Chase the reference to get the final location
- let (location, value) = Self::get_split_ref(location)?;
- if let RwLockStorageEntryData::Rc(data) = &value.data {
- data.add_ref();
- } else {
- unreachable!()
- }
- Ok(Self::create_new(
- RwLockStorageEntryData::Reference(location),
- location
- .location
- .created_at()
- .unwrap_or(std::panic::Location::caller()),
- ))
- }
- fn change_reference(
- location: GenerationalPointer<Self>,
- other: GenerationalPointer<Self>,
- ) -> BorrowResult {
- if location == other {
- return Ok(());
- }
- let (other_final, other_write) = Self::get_split_ref(other)?;
- let mut write = location.storage.data.write();
- // First check if the generation is still valid
- if !write.valid(&location.location) {
- return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
- location.location,
- )));
- }
- if let (RwLockStorageEntryData::Reference(reference), RwLockStorageEntryData::Rc(data)) =
- (&mut write.data, &other_write.data)
- {
- if reference == &other_final {
- return Ok(());
- }
- drop_ref(*reference);
- *reference = other_final;
- data.add_ref();
- } else {
- tracing::trace!(
- "References should always point to a data entry directly found {:?} instead",
- other_write.data
- );
- return Err(BorrowError::Dropped(ValueDroppedError::new_for_location(
- other_final.location,
- )));
- }
- Ok(())
- }
- }
|