diff options
author | HampusM <hampus@hampusmat.com> | 2024-03-29 14:20:21 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-03-29 14:20:21 +0100 |
commit | 61dfcf1ba2049bf0375821652e49b0e4c4147623 (patch) | |
tree | 3eaa2624523c893cb12b08595c4dd9e5250728c4 /ecs/src/lock.rs | |
parent | 96ba84e42c77147d297b358c944a48fee3785ae1 (diff) |
feat(ecs): make World unwind safe
Diffstat (limited to 'ecs/src/lock.rs')
-rw-r--r-- | ecs/src/lock.rs | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/ecs/src/lock.rs b/ecs/src/lock.rs new file mode 100644 index 0000000..ff46761 --- /dev/null +++ b/ecs/src/lock.rs @@ -0,0 +1,130 @@ +use std::ops::{Deref, DerefMut}; +use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError}; + +use crate::type_name::TypeName; + +#[derive(Debug, Default)] +pub struct Lock<Value> +where + Value: TypeName, +{ + inner: RwLock<Value>, +} + +impl<Value> Lock<Value> +where + Value: TypeName, +{ + pub fn new(value: Value) -> Self + { + Self { inner: RwLock::new(value) } + } + + 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()), + })?; + + #[cfg(feature = "debug")] + tracing::trace!("Acquired lock to value of type {}", guard.type_name()); + + Ok(ReadGuard { inner: guard }) + } + + 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()), + })?; + + #[cfg(feature = "debug")] + tracing::trace!( + "Acquired mutable lock to value of type {}", + guard.type_name() + ); + + Ok(WriteGuard { inner: guard }) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum Error +{ + #[error("Lock is unavailable")] + Unavailable, +} + +#[derive(Debug)] +pub struct ReadGuard<'guard, Value> +where + Value: TypeName, +{ + inner: RwLockReadGuard<'guard, Value>, +} + +impl<'guard, Value> Deref for ReadGuard<'guard, Value> +where + Value: TypeName, +{ + type Target = Value; + + fn deref(&self) -> &Self::Target + { + &self.inner + } +} + +impl<'guard, Value> Drop for ReadGuard<'guard, Value> +where + Value: TypeName, +{ + fn drop(&mut self) + { + #[cfg(feature = "debug")] + tracing::trace!("Dropped lock to value of type {}", self.type_name()); + } +} + +#[derive(Debug)] +pub struct WriteGuard<'guard, Value> +where + Value: TypeName, +{ + inner: RwLockWriteGuard<'guard, Value>, +} + +impl<'guard, Value> Deref for WriteGuard<'guard, Value> +where + Value: TypeName, +{ + type Target = Value; + + fn deref(&self) -> &Self::Target + { + &self.inner + } +} + +impl<'guard, Value> DerefMut for WriteGuard<'guard, Value> +where + Value: TypeName, +{ + fn deref_mut(&mut self) -> &mut Self::Target + { + &mut self.inner + } +} + +impl<'guard, Value> Drop for WriteGuard<'guard, Value> +where + Value: TypeName, +{ + fn drop(&mut self) + { + #[cfg(feature = "debug")] + tracing::trace!("Dropped mutable lock to value of type {}", self.type_name()); + } +} |