use std::mem::forget; use std::ops::{Deref, DerefMut}; use parking_lot::{ MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, }; #[derive(Debug)] pub struct Lock { inner: RwLock, value_type_name: &'static str, } impl Lock { 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, 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, 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, }) } } #[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 map( self, func: impl FnOnce(&Value) -> &NewValue, ) -> MappedReadGuard<'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); MappedReadGuard { inner: RwLockReadGuard::map(inner, func), value_type_name, } } } impl Deref for ReadGuard<'_, Value> { type Target = Value; fn deref(&self) -> &Self::Target { &self.inner } } impl 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 Deref for MappedReadGuard<'_, Value> { type Target = Value; fn deref(&self) -> &Self::Target { &self.inner } } impl 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 map( 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 Deref for WriteGuard<'_, Value> { type Target = Value; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for WriteGuard<'_, Value> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl 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 Deref for MappedWriteGuard<'_, Value> { type Target = Value; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for MappedWriteGuard<'_, Value> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl Drop for MappedWriteGuard<'_, Value> { fn drop(&mut self) { tracing::trace!( "Dropped mapped mutable lock to value of type {}", self.value_type_name ); } }