use std::{
cell::UnsafeCell,
sync::atomic::{AtomicBool, Ordering},
};
#[derive(Debug)]
pub struct Mutex<T> {
data: UnsafeCell<T>,
lock: AtomicBool,
}
#[derive(Debug)]
pub struct MutexGuard<'a, T: 'a> {
mutex: &'a Mutex<T>,
}
unsafe impl<T: Send> Sync for Mutex<T> {}
unsafe impl<T: Send> Send for Mutex<T> {}
unsafe impl<T: Sync> Sync for MutexGuard<'_, T> {}
unsafe impl<T: Send> Send for MutexGuard<'_, T> {}
impl<T> Mutex<T> {
pub(super) const fn new(data: T) -> Self {
Self { data: UnsafeCell::new(data), lock: AtomicBool::new(false) }
}
pub(super) fn lock(&self) -> MutexGuard<'_, T> {
loop {
if self
.lock
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
return MutexGuard { mutex: self };
}
while self.lock.load(Ordering::Relaxed) {
core::hint::spin_loop();
}
}
}
pub(super) fn try_lock(&self) -> Result<MutexGuard<'_, T>, ()> {
loop {
if self
.lock
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
return Ok(MutexGuard { mutex: self });
}
while self.lock.load(Ordering::Relaxed) {
core::hint::spin_loop();
}
}
}
}
impl<T> core::ops::Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.data.get() }
}
}
impl<T> core::ops::DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.mutex.lock.store(false, Ordering::Release);
}
}