diff options
author | HampusM <hampus@hampusmat.com> | 2025-02-04 19:04:51 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2025-02-04 19:04:51 +0100 |
commit | a735f352f789a440508cf9dd1c554b4d1db6cbb7 (patch) | |
tree | e1147eda5793cc814640dada77f109631c6beaad /ecs/src/lock.rs | |
parent | 76d782195e3cc19832ad57ffffda4e953c6970b3 (diff) |
fix(ecs): make ComponentRef & ComponentRefMut deref not able to panic
Diffstat (limited to 'ecs/src/lock.rs')
-rw-r--r-- | ecs/src/lock.rs | 122 |
1 files changed, 120 insertions, 2 deletions
diff --git a/ecs/src/lock.rs b/ecs/src/lock.rs index 74b0415..c700098 100644 --- a/ecs/src/lock.rs +++ b/ecs/src/lock.rs @@ -1,7 +1,13 @@ -use std::mem::transmute; +use std::mem::{forget, transmute}; use std::ops::{Deref, DerefMut}; -use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use parking_lot::{ + MappedRwLockReadGuard, + MappedRwLockWriteGuard, + RwLock, + RwLockReadGuard, + RwLockWriteGuard, +}; use crate::type_name::TypeName; @@ -79,6 +85,23 @@ impl<'guard, Value> ReadGuard<'guard, Value> where Value: TypeName, { + pub fn map<NewValue>( + self, + func: impl FnOnce(&Value) -> &NewValue, + ) -> MappedReadGuard<'guard, NewValue> + where + NewValue: TypeName, + { + // The 'inner' field cannot be moved out of ReadGuard in a normal way since + // ReadGuard implements Drop + let inner = unsafe { std::ptr::read(&self.inner) }; + forget(self); + + MappedReadGuard { + inner: RwLockReadGuard::map(inner, func), + } + } + /// Converts the `ReadGuard` to a `ReadGuard` with a possibly longer lifetime. /// /// # Safety @@ -114,6 +137,36 @@ where } #[derive(Debug)] +pub struct MappedReadGuard<'guard, Value> +where + Value: TypeName, +{ + inner: MappedRwLockReadGuard<'guard, Value>, +} + +impl<'guard, Value> Deref for MappedReadGuard<'guard, Value> +where + Value: TypeName, +{ + type Target = Value; + + fn deref(&self) -> &Self::Target + { + &self.inner + } +} + +impl<'guard, Value> Drop for MappedReadGuard<'guard, Value> +where + Value: TypeName, +{ + fn drop(&mut self) + { + tracing::trace!("Dropped mapped lock to value of type {}", self.type_name()); + } +} + +#[derive(Debug)] pub struct WriteGuard<'guard, Value> where Value: TypeName, @@ -121,6 +174,28 @@ where inner: RwLockWriteGuard<'guard, Value>, } +impl<'guard, Value> WriteGuard<'guard, Value> +where + Value: TypeName, +{ + pub fn map<NewValue>( + self, + func: impl FnOnce(&mut Value) -> &mut NewValue, + ) -> MappedWriteGuard<'guard, NewValue> + where + NewValue: TypeName, + { + // The 'inner' field cannot be moved out of ReadGuard in a normal way since + // ReadGuard implements Drop + let inner = unsafe { std::ptr::read(&self.inner) }; + forget(self); + + MappedWriteGuard { + inner: RwLockWriteGuard::map(inner, func), + } + } +} + impl<'guard, Value> Deref for WriteGuard<'guard, Value> where Value: TypeName, @@ -152,3 +227,46 @@ where tracing::trace!("Dropped mutable lock to value of type {}", self.type_name()); } } + +#[derive(Debug)] +pub struct MappedWriteGuard<'guard, Value> +where + Value: TypeName, +{ + inner: MappedRwLockWriteGuard<'guard, Value>, +} + +impl<'guard, Value> Deref for MappedWriteGuard<'guard, Value> +where + Value: TypeName, +{ + type Target = Value; + + fn deref(&self) -> &Self::Target + { + &self.inner + } +} + +impl<'guard, Value> DerefMut for MappedWriteGuard<'guard, Value> +where + Value: TypeName, +{ + fn deref_mut(&mut self) -> &mut Self::Target + { + &mut self.inner + } +} + +impl<'guard, Value> Drop for MappedWriteGuard<'guard, Value> +where + Value: TypeName, +{ + fn drop(&mut self) + { + tracing::trace!( + "Dropped mapped mutable lock to value of type {}", + self.type_name() + ); + } +} |