summaryrefslogtreecommitdiff
path: root/engine-ecs/src/lock.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src/lock.rs')
-rw-r--r--engine-ecs/src/lock.rs259
1 files changed, 259 insertions, 0 deletions
diff --git a/engine-ecs/src/lock.rs b/engine-ecs/src/lock.rs
new file mode 100644
index 0000000..fe4e08b
--- /dev/null
+++ b/engine-ecs/src/lock.rs
@@ -0,0 +1,259 @@
+use std::any::type_name;
+use std::mem::forget;
+use std::ops::{Deref, DerefMut};
+
+use parking_lot::{
+ MappedRwLockReadGuard,
+ MappedRwLockWriteGuard,
+ RwLock,
+ RwLockReadGuard,
+ RwLockWriteGuard,
+};
+
+#[derive(Debug)]
+pub struct Lock<Value>
+{
+ inner: RwLock<Value>,
+ value_type_name: &'static str,
+}
+
+impl<Value> Lock<Value>
+{
+ pub fn new(value: Value, value_type_name: &'static str) -> Self
+ {
+ 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>
+ {
+ let guard = self.inner.try_read().ok_or(Error::ReadUnavailable)?;
+
+ tracing::trace!("Acquired lock to value of type {}", self.value_type_name);
+
+ 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>
+ {
+ let guard = self.inner.try_write().ok_or(Error::WriteUnavailable)?;
+
+ tracing::trace!(
+ "Acquired mutable lock to value of type {}",
+ self.value_type_name
+ );
+
+ Ok(WriteGuard {
+ inner: guard,
+ value_type_name: self.value_type_name,
+ })
+ }
+}
+
+impl<Value: Default + 'static> Default for Lock<Value>
+{
+ fn default() -> Self
+ {
+ Self::new(Value::default(), type_name::<Value>())
+ }
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error
+{
+ #[error("Lock is unavailable for reading")]
+ ReadUnavailable,
+
+ #[error("Lock is unavailable for writing")]
+ WriteUnavailable,
+}
+
+#[derive(Debug)]
+pub struct ReadGuard<'guard, Value>
+{
+ inner: RwLockReadGuard<'guard, Value>,
+ value_type_name: &'static str,
+}
+
+impl<'guard, Value> ReadGuard<'guard, Value>
+{
+ pub fn try_map<NewValue>(
+ this: Self,
+ func: impl FnOnce(&Value) -> Option<&NewValue>,
+ ) -> Result<MappedReadGuard<'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 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<Value> Deref for ReadGuard<'_, Value>
+{
+ type Target = Value;
+
+ fn deref(&self) -> &Self::Target
+ {
+ &self.inner
+ }
+}
+
+impl<Value> Drop for ReadGuard<'_, Value>
+{
+ fn drop(&mut self)
+ {
+ 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>
+{
+ inner: RwLockWriteGuard<'guard, Value>,
+ value_type_name: &'static str,
+}
+
+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;
+
+ 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
+ );
+ }
+}