use std::sync::{
Mutex,
RwLock,
};
use parking_lot::Mutex as ParkingLotMutex;
use super::try_lock_error::TryLockError;
pub trait Lock<T: ?Sized> {
fn read<R, F>(&self, f: F) -> R
where
F: FnOnce(&T) -> R;
fn write<R, F>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R;
fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&T) -> R;
fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&mut T) -> R;
}
impl<T: ?Sized> Lock<T> for Mutex<T> {
#[inline]
fn read<R, F>(&self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
let guard = self.lock().unwrap();
f(&*guard)
}
#[inline]
fn write<R, F>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
let mut guard = self.lock().unwrap();
f(&mut *guard)
}
#[inline]
fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&T) -> R,
{
match self.try_lock() {
Ok(guard) => Ok(f(&*guard)),
Err(std::sync::TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
Err(std::sync::TryLockError::Poisoned(_)) => Err(TryLockError::Poisoned),
}
}
#[inline]
fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&mut T) -> R,
{
match self.try_lock() {
Ok(mut guard) => Ok(f(&mut *guard)),
Err(std::sync::TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
Err(std::sync::TryLockError::Poisoned(_)) => Err(TryLockError::Poisoned),
}
}
}
impl<T: ?Sized> Lock<T> for RwLock<T> {
#[inline]
fn read<R, F>(&self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
let guard = self.read().unwrap();
f(&*guard)
}
#[inline]
fn write<R, F>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
let mut guard = self.write().unwrap();
f(&mut *guard)
}
#[inline]
fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&T) -> R,
{
match self.try_read() {
Ok(guard) => Ok(f(&*guard)),
Err(std::sync::TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
Err(std::sync::TryLockError::Poisoned(_)) => Err(TryLockError::Poisoned),
}
}
#[inline]
fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&mut T) -> R,
{
match self.try_write() {
Ok(mut guard) => Ok(f(&mut *guard)),
Err(std::sync::TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
Err(std::sync::TryLockError::Poisoned(_)) => Err(TryLockError::Poisoned),
}
}
}
impl<T: ?Sized> Lock<T> for ParkingLotMutex<T> {
#[inline]
fn read<R, F>(&self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
let guard = self.lock();
f(&*guard)
}
#[inline]
fn write<R, F>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
let mut guard = self.lock();
f(&mut *guard)
}
#[inline]
fn try_read<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&T) -> R,
{
self.try_lock()
.map(|guard| f(&*guard))
.ok_or(TryLockError::WouldBlock)
}
#[inline]
fn try_write<R, F>(&self, f: F) -> Result<R, TryLockError>
where
F: FnOnce(&mut T) -> R,
{
self.try_lock()
.map(|mut guard| f(&mut *guard))
.ok_or(TryLockError::WouldBlock)
}
}