use std::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, Ordering},
};
pub struct FusedRwLock<T: ?Sized> {
inner: parking_lot::RwLock<()>,
locked: AtomicBool,
object: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send> Send for FusedRwLock<T> {}
unsafe impl<T: ?Sized + Send + Sync> Sync for FusedRwLock<T> {}
impl<T: Default> Default for FusedRwLock<T> {
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T> FusedRwLock<T> {
pub const fn new(x: T) -> Self {
Self {
inner: parking_lot::const_rwlock(()),
locked: AtomicBool::new(false),
object: UnsafeCell::new(x),
}
}
pub fn into_inner(self) -> T {
self.object.into_inner()
}
}
impl<T: ?Sized> FusedRwLock<T> {
pub fn try_get_mut(&mut self) -> Option<&mut T> {
if *self.locked.get_mut() {
Some(self.object.get_mut())
} else {
None
}
}
pub unsafe fn get_mut_unlocked(&mut self) -> &mut T {
self.object.get_mut()
}
pub fn is_locked(&self) -> bool {
self.locked.load(Ordering::Relaxed)
}
pub fn lock(&self) {
let _guard = self.inner.read();
self.locked
.store(true, std::sync::atomic::Ordering::Release)
}
pub fn try_read(&self) -> Option<&T> {
if self.locked.load(Ordering::Acquire) {
Some(unsafe { &*self.object.get() })
} else {
None
}
}
pub fn read(&self) -> &T {
if !self.is_locked() {
self.lock();
}
self.try_read().unwrap()
}
pub fn try_write(&self) -> Option<FusedRwLockGuard<T>> {
if !self.is_locked() {
let guard = self.inner.write();
if !self.is_locked() {
Some(FusedRwLockGuard {
_guard: guard,
inner: unsafe { &mut *self.object.get() },
})
} else {
None
}
} else {
None
}
}
}
pub struct FusedRwLockGuard<'a, T: ?Sized> {
inner: &'a mut T,
_guard: parking_lot::RwLockWriteGuard<'a, ()>,
}
impl<'a, T: ?Sized> Deref for FusedRwLockGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.inner
}
}
impl<'a, T: ?Sized> DerefMut for FusedRwLockGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
self.inner
}
}