use std::{
cell::UnsafeCell,
marker::PhantomData,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, Ordering},
};
pub struct TryLock<T> {
is_locked: AtomicBool,
value: UnsafeCell<T>,
}
impl<T> TryLock<T> {
#[inline]
pub const fn new(value: T) -> TryLock<T> {
TryLock {
is_locked: AtomicBool::new(false),
value: UnsafeCell::new(value),
}
}
#[inline]
pub fn try_read_lock(&self) -> Option<TryLockGuard<'_, T, Read>> {
self.try_lock()
}
#[inline]
pub fn try_write_lock(&self) -> Option<TryLockGuard<'_, T, Write>> {
self.try_lock()
}
#[inline]
fn try_lock<K>(&self) -> Option<TryLockGuard<'_, T, K>> {
if !self.is_locked.swap(true, Ordering::Acquire) {
Some(TryLockGuard { lock: self, _phantom: PhantomData })
} else {
None
}
}
}
pub struct Read;
pub struct Write;
pub struct TryLockGuard<'lock, T: 'lock, K> {
lock: &'lock TryLock<T>,
_phantom: PhantomData<(*mut T, K)>,
}
impl<'lock, T, K> Drop for TryLockGuard<'lock, T, K> {
fn drop(&mut self) {
self.lock.is_locked.store(false, Ordering::Release);
}
}
impl<'lock, T, K> Deref for TryLockGuard<'lock, T, K> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.lock.value.get() }
}
}
impl<'lock, T> DerefMut for TryLockGuard<'lock, T, Write> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.lock.value.get() }
}
}