#![allow(dead_code)]
use std::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
mem::{transmute_copy, ManuallyDrop},
sync::atomic::{
AtomicU8,
Ordering::{self, *},
},
};
pub struct AtomicEnum<E: ReprU8>(AtomicU8, PhantomData<E>);
impl<E: ReprU8> AtomicEnum<E> {
#[inline]
pub fn new(val: E) -> Self { Self(AtomicU8::new(val.to_u8()), PhantomData) }
#[inline]
pub fn load(&self, ordering: Ordering) -> E {
let v = self.0.load(ordering);
unsafe { E::from_u8(v) }
}
#[inline]
pub fn store(&self, val: E, ordering: Ordering) { self.0.store(val.to_u8(), ordering) }
#[inline]
pub fn compare_exchange(
&self,
current: E,
new: E,
success: Ordering,
failure: Ordering,
) -> Result<E, E> {
let unwr = |v: u8| unsafe { E::from_u8(v) };
self.0
.compare_exchange(current.to_u8(), new.to_u8(), success, failure)
.map(unwr)
.map_err(unwr)
}
#[inline]
pub fn get_mut(&mut self) -> &mut E {
unsafe { &mut *self.0.as_ptr().cast() }
}
}
impl<E: ReprU8 + Debug> Debug for AtomicEnum<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let val: E = unsafe { E::from_u8(self.0.load(SeqCst)) };
f.debug_tuple("AtomicEnum").field(&val).finish()
}
}
pub unsafe trait ReprU8: Sized {
#[inline(always)]
fn to_u8(self) -> u8 {
let slf = ManuallyDrop::new(self);
unsafe { transmute_copy(&slf) }
}
#[inline(always)]
unsafe fn from_u8(v: u8) -> Self { unsafe { transmute_copy(&v) } }
}