diff options
Diffstat (limited to 'ecs/src/lock.rs')
-rw-r--r-- | ecs/src/lock.rs | 227 |
1 files changed, 162 insertions, 65 deletions
diff --git a/ecs/src/lock.rs b/ecs/src/lock.rs index fbc6842..fe4e08b 100644 --- a/ecs/src/lock.rs +++ b/ecs/src/lock.rs @@ -1,105 +1,120 @@ -use std::mem::transmute; +use std::any::type_name; +use std::mem::forget; use std::ops::{Deref, DerefMut}; -use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError}; -use crate::type_name::TypeName; +use parking_lot::{ + MappedRwLockReadGuard, + MappedRwLockWriteGuard, + RwLock, + RwLockReadGuard, + RwLockWriteGuard, +}; -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Lock<Value> -where - Value: TypeName, { inner: RwLock<Value>, + value_type_name: &'static str, } impl<Value> Lock<Value> -where - Value: TypeName, { - pub fn new(value: Value) -> Self + pub fn new(value: Value, value_type_name: &'static str) -> Self { - Self { inner: RwLock::new(value) } + Self { + inner: RwLock::new(value), + value_type_name, + } } /// Tries to a acquire a handle to the resource with read access. /// /// # Errors /// Returns `Err` if unavailable (A mutable handle is hold). - pub fn read_nonblock(&self) -> Result<ReadGuard<Value>, Error> + pub fn read_nonblock(&self) -> Result<ReadGuard<'_, Value>, Error> { - let guard = self.inner.try_read().or_else(|err| match err { - TryLockError::WouldBlock => Err(Error::Unavailable), - TryLockError::Poisoned(poison_err) => Ok(poison_err.into_inner()), - })?; + let guard = self.inner.try_read().ok_or(Error::ReadUnavailable)?; - #[cfg(feature = "debug")] - tracing::trace!("Acquired lock to value of type {}", guard.type_name()); + tracing::trace!("Acquired lock to value of type {}", self.value_type_name); - Ok(ReadGuard { inner: guard }) + Ok(ReadGuard { + inner: guard, + value_type_name: self.value_type_name, + }) } /// Tries to a acquire a handle to the resource with mutable access. /// /// # Errors /// Returns `Err` if unavailable (A mutable or immutable handle is hold). - pub fn write_nonblock(&self) -> Result<WriteGuard<Value>, Error> + pub fn write_nonblock(&self) -> Result<WriteGuard<'_, Value>, Error> { - let guard = self.inner.try_write().or_else(|err| match err { - TryLockError::WouldBlock => Err(Error::Unavailable), - TryLockError::Poisoned(poison_err) => Ok(poison_err.into_inner()), - })?; + let guard = self.inner.try_write().ok_or(Error::WriteUnavailable)?; - #[cfg(feature = "debug")] tracing::trace!( "Acquired mutable lock to value of type {}", - guard.type_name() + self.value_type_name ); - Ok(WriteGuard { inner: guard }) + Ok(WriteGuard { + inner: guard, + value_type_name: self.value_type_name, + }) } +} - pub fn into_inner(self) -> Value +impl<Value: Default + 'static> Default for Lock<Value> +{ + fn default() -> Self { - self.inner - .into_inner() - .unwrap_or_else(PoisonError::into_inner) + Self::new(Value::default(), type_name::<Value>()) } } #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("Lock is unavailable")] - Unavailable, + #[error("Lock is unavailable for reading")] + ReadUnavailable, + + #[error("Lock is unavailable for writing")] + WriteUnavailable, } #[derive(Debug)] pub struct ReadGuard<'guard, Value> -where - Value: TypeName, { inner: RwLockReadGuard<'guard, Value>, + value_type_name: &'static str, } impl<'guard, Value> ReadGuard<'guard, Value> -where - Value: TypeName, { - /// Converts the `ReadGuard` to a `ReadGuard` with a possibly longer lifetime. - /// - /// # Safety - /// The returned `ReadGuard` must **NOT** be used for longer than the original - /// lifetime. - #[must_use] - pub unsafe fn upgrade_lifetime<'new>(self) -> ReadGuard<'new, Value> + pub fn try_map<NewValue>( + this: Self, + func: impl FnOnce(&Value) -> Option<&NewValue>, + ) -> Result<MappedReadGuard<'guard, NewValue>, Self> { - unsafe { transmute(self) } + let value_type_name = this.value_type_name; + + // The 'inner' field cannot be moved out of ReadGuard in a normal way since + // ReadGuard implements Drop + let inner = unsafe { std::ptr::read(&raw const this.inner) }; + forget(this); + + match RwLockReadGuard::try_map(inner, func) { + Ok(mapped_guard) => { + Ok(MappedReadGuard { inner: mapped_guard, value_type_name }) + } + Err(unmapped_guard) => Err(Self { + inner: unmapped_guard, + value_type_name, + }), + } } } -impl<'guard, Value> Deref for ReadGuard<'guard, Value> -where - Value: TypeName, +impl<Value> Deref for ReadGuard<'_, Value> { type Target = Value; @@ -109,28 +124,112 @@ where } } -impl<'guard, Value> Drop for ReadGuard<'guard, Value> -where - Value: TypeName, +impl<Value> Drop for ReadGuard<'_, Value> { fn drop(&mut self) { - #[cfg(feature = "debug")] - tracing::trace!("Dropped lock to value of type {}", self.type_name()); + tracing::trace!("Dropped lock to value of type {}", self.value_type_name); + } +} + +#[derive(Debug)] +pub struct MappedReadGuard<'guard, Value> +{ + inner: MappedRwLockReadGuard<'guard, Value>, + value_type_name: &'static str, +} + +impl<Value> Deref for MappedReadGuard<'_, Value> +{ + type Target = Value; + + fn deref(&self) -> &Self::Target + { + &self.inner + } +} + +impl<Value> Drop for MappedReadGuard<'_, Value> +{ + fn drop(&mut self) + { + tracing::trace!( + "Dropped mapped lock to value of type {}", + self.value_type_name + ); } } #[derive(Debug)] pub struct WriteGuard<'guard, Value> -where - Value: TypeName, { inner: RwLockWriteGuard<'guard, Value>, + value_type_name: &'static str, } -impl<'guard, Value> Deref for WriteGuard<'guard, Value> -where - Value: TypeName, +impl<'guard, Value> WriteGuard<'guard, Value> +{ + pub fn try_map<NewValue>( + this: Self, + func: impl FnOnce(&mut Value) -> Option<&mut NewValue>, + ) -> Result<MappedWriteGuard<'guard, NewValue>, Self> + { + let value_type_name = this.value_type_name; + + // The 'inner' field cannot be moved out of ReadGuard in a normal way since + // ReadGuard implements Drop + let inner = unsafe { std::ptr::read(&raw const this.inner) }; + forget(this); + + match RwLockWriteGuard::try_map(inner, func) { + Ok(mapped_guard) => { + Ok(MappedWriteGuard { inner: mapped_guard, value_type_name }) + } + Err(unmapped_guard) => Err(Self { + inner: unmapped_guard, + value_type_name, + }), + } + } +} + +impl<Value> Deref for WriteGuard<'_, Value> +{ + type Target = Value; + + fn deref(&self) -> &Self::Target + { + &self.inner + } +} + +impl<Value> DerefMut for WriteGuard<'_, Value> +{ + fn deref_mut(&mut self) -> &mut Self::Target + { + &mut self.inner + } +} + +impl<Value> Drop for WriteGuard<'_, Value> +{ + fn drop(&mut self) + { + tracing::trace!( + "Dropped mutable lock to value of type {}", + self.value_type_name + ); + } +} + +#[derive(Debug)] +pub struct MappedWriteGuard<'guard, Value> +{ + inner: MappedRwLockWriteGuard<'guard, Value>, + value_type_name: &'static str, +} + +impl<Value> Deref for MappedWriteGuard<'_, Value> { type Target = Value; @@ -140,9 +239,7 @@ where } } -impl<'guard, Value> DerefMut for WriteGuard<'guard, Value> -where - Value: TypeName, +impl<Value> DerefMut for MappedWriteGuard<'_, Value> { fn deref_mut(&mut self) -> &mut Self::Target { @@ -150,13 +247,13 @@ where } } -impl<'guard, Value> Drop for WriteGuard<'guard, Value> -where - Value: TypeName, +impl<Value> Drop for MappedWriteGuard<'_, Value> { fn drop(&mut self) { - #[cfg(feature = "debug")] - tracing::trace!("Dropped mutable lock to value of type {}", self.type_name()); + tracing::trace!( + "Dropped mapped mutable lock to value of type {}", + self.value_type_name + ); } } |