summaryrefslogtreecommitdiff
path: root/ecs/src/lock.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/lock.rs')
-rw-r--r--ecs/src/lock.rs210
1 files changed, 144 insertions, 66 deletions
diff --git a/ecs/src/lock.rs b/ecs/src/lock.rs
index fbc6842..0b36922 100644
--- a/ecs/src/lock.rs
+++ b/ecs/src/lock.rs
@@ -1,24 +1,29 @@
-use std::mem::transmute;
+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.
@@ -27,15 +32,14 @@ where
/// Returns `Err` if unavailable (A mutable handle is hold).
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.
@@ -44,62 +48,59 @@ where
/// Returns `Err` if unavailable (A mutable or immutable handle is hold).
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 })
- }
-
- pub fn into_inner(self) -> Value
- {
- self.inner
- .into_inner()
- .unwrap_or_else(PoisonError::into_inner)
+ Ok(WriteGuard {
+ inner: guard,
+ value_type_name: self.value_type_name,
+ })
}
}
#[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 map<NewValue>(
+ self,
+ func: impl FnOnce(&Value) -> &NewValue,
+ ) -> MappedReadGuard<'guard, NewValue>
{
- unsafe { transmute(self) }
+ let value_type_name = self.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(&self.inner) };
+ forget(self);
+
+ MappedReadGuard {
+ inner: RwLockReadGuard::map(inner, func),
+ 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 +110,71 @@ 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> WriteGuard<'guard, Value>
+{
+ pub fn map<NewValue>(
+ self,
+ func: impl FnOnce(&mut Value) -> &mut NewValue,
+ ) -> MappedWriteGuard<'guard, NewValue>
+ {
+ let value_type_name = self.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(&self.inner) };
+ forget(self);
+
+ MappedWriteGuard {
+ inner: RwLockWriteGuard::map(inner, func),
+ value_type_name,
+ }
+ }
}
-impl<'guard, Value> Deref for WriteGuard<'guard, Value>
-where
- Value: TypeName,
+impl<Value> Deref for WriteGuard<'_, Value>
{
type Target = Value;
@@ -140,9 +184,7 @@ where
}
}
-impl<'guard, Value> DerefMut for WriteGuard<'guard, Value>
-where
- Value: TypeName,
+impl<Value> DerefMut for WriteGuard<'_, Value>
{
fn deref_mut(&mut self) -> &mut Self::Target
{
@@ -150,13 +192,49 @@ where
}
}
-impl<'guard, Value> Drop for WriteGuard<'guard, Value>
-where
- Value: TypeName,
+impl<Value> Drop for WriteGuard<'_, Value>
{
fn drop(&mut self)
{
- #[cfg(feature = "debug")]
- tracing::trace!("Dropped mutable lock to value of type {}", self.type_name());
+ 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;
+
+ fn deref(&self) -> &Self::Target
+ {
+ &self.inner
+ }
+}
+
+impl<Value> DerefMut for MappedWriteGuard<'_, Value>
+{
+ fn deref_mut(&mut self) -> &mut Self::Target
+ {
+ &mut self.inner
+ }
+}
+
+impl<Value> Drop for MappedWriteGuard<'_, Value>
+{
+ fn drop(&mut self)
+ {
+ tracing::trace!(
+ "Dropped mapped mutable lock to value of type {}",
+ self.value_type_name
+ );
}
}