use std::mem::transmute; use std::ops::{Deref, DerefMut}; use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError}; use crate::type_name::TypeName; #[derive(Debug, Default)] pub struct Lock where Value: TypeName, { inner: RwLock, } impl Lock where Value: TypeName, { pub fn new(value: Value) -> Self { Self { inner: RwLock::new(value) } } /// 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, 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 }) } /// 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, 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 }) } pub fn into_inner(self) -> Value { self.inner .into_inner() .unwrap_or_else(PoisonError::into_inner) } } #[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> 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> { unsafe { transmute(self) } } } 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()); } }