use crate::misc::PhantomMutexGuard;
use crate::result::{TryLockError, TryLockResult};
use std::fmt::{self, Debug, Display};
use std::sync::atomic::{AtomicU8, Ordering};
use std::thread;
pub struct Mutex8(AtomicU8);
impl Mutex8 {
pub const LEN: usize = 8;
#[inline]
pub const fn new() -> Self {
Self(AtomicU8::new(0))
}
}
impl Display for Mutex8 {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Mutex8")
}
}
impl Debug for Mutex8 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mutex8")
.field("locked_bits", &self.locked_bits())
.finish()
}
}
impl Mutex8 {
#[inline]
pub fn lock(&self, lock_bits: u8) -> Mutex8Guard {
let mut expected = 0;
while {
debug_assert_eq!(0, expected & lock_bits);
let locked = expected + lock_bits;
let current = self.0.compare_and_swap(expected, locked, Ordering::Acquire);
if expected == current {
false
} else if current & lock_bits == 0 {
expected = current;
true
} else {
thread::yield_now();
true
}
} {}
Mutex8Guard {
bits: lock_bits,
mutex8: &self,
_phantom: Default::default(),
}
}
#[inline]
pub fn try_lock(&self, lock_bits: u8) -> TryLockResult<Mutex8Guard> {
let mut expected = 0;
while {
debug_assert_eq!(0, expected & lock_bits);
let locked = expected + lock_bits;
let current = self.0.compare_and_swap(expected, locked, Ordering::Acquire);
if expected == current {
false
} else if current & lock_bits == 0 {
expected = current;
true
} else {
return Err(TryLockError::WouldBlock);
}
} {}
Ok(Mutex8Guard {
bits: lock_bits,
mutex8: &self,
_phantom: Default::default(),
})
}
#[inline]
pub fn locked_bits(&self) -> u8 {
self.0.load(Ordering::Relaxed)
}
pub const fn len(&self) -> usize {
Self::LEN
}
}
#[must_use = "if unused the Mutex8 will immediately unlock"]
pub struct Mutex8Guard<'a> {
bits: u8,
mutex8: &'a Mutex8,
_phantom: PhantomMutexGuard<'a, u8>, }
impl Drop for Mutex8Guard<'_> {
#[inline]
fn drop(&mut self) {
if self.bits != 0 {
self.release(self.bits);
}
}
}
impl Display for Mutex8Guard<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Mutex8Guard")
}
}
impl Debug for Mutex8Guard<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mutex8Guard")
.field("lock_bits", &self.lock_bits())
.finish()
}
}
impl Mutex8Guard<'_> {
#[inline]
pub fn release(&mut self, lock_bits: u8) {
assert_eq!(lock_bits, self.bits & lock_bits);
let mut expected = self.bits;
while {
debug_assert_eq!(self.bits, expected & self.bits);
let unlocked = expected - lock_bits;
let current = self
.mutex8
.0
.compare_and_swap(expected, unlocked, Ordering::Release);
if current == expected {
self.bits -= lock_bits;
false
} else {
expected = current;
true
}
} {}
}
#[inline]
pub fn lock_bits(&self) -> u8 {
self.bits
}
}