use parking_lot::{Condvar, Mutex, RwLock, RwLockReadGuard};
use std::ops::Deref;
pub struct Lock<T: ?Sized> {
wants_write: (Mutex<bool>, Condvar),
inner: RwLock<T>, }
impl<T> Lock<T> {
pub fn new(user_data: T) -> Lock<T> {
Lock {
wants_write: (Mutex::new(false), Condvar::new()),
inner: RwLock::new(user_data),
}
}
}
impl<T: ?Sized> Lock<T> {
pub fn read(&self) -> LockReadGuard<T> {
let (ref lock, ref cvar) = &self.wants_write;
let mut wants_write = lock.lock();
while *wants_write {
cvar.wait(&mut wants_write);
}
LockReadGuard {
wants_write: &self.wants_write,
inner: self.inner.read(),
}
}
}
pub struct LockReadGuard<'a, T: 'a + ?Sized> {
wants_write: &'a (Mutex<bool>, Condvar),
inner: RwLockReadGuard<'a, T>,
}
impl<'a, T: ?Sized> LockReadGuard<'a, T> {
pub fn try_writeable<U, P: FnOnce(&T), F: FnOnce(&mut T) -> U>(
&mut self,
prep_func: P,
mut_func: F,
) -> Option<U> {
{
let &(ref lock, cvar) = &self.wants_write;
let mut wants_write = lock.lock();
RwLockReadGuard::unlocked(&mut self.inner, move || {
while *wants_write {
cvar.wait(&mut wants_write);
}
*wants_write = true;
});
}
prep_func(&*self.inner);
let lock = RwLockReadGuard::rwlock(&self.inner);
let ret = Some(RwLockReadGuard::unlocked(&mut self.inner, move || {
let mut write_access = lock.write();
mut_func(&mut *write_access)
}));
let (ref lock, ref cvar) = &self.wants_write;
let mut wants_write = lock.lock();
*wants_write = false;
cvar.notify_all();
ret
}
}
impl<'a, T: ?Sized> Deref for LockReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
&self.inner
}
}