use core::{
marker::PhantomData,
mem::align_of,
ptr::{from_mut, from_ref, null_mut},
sync::atomic::{AtomicPtr, Ordering},
};
#[repr(transparent)]
pub struct State<T>(usize, PhantomData<T>);
impl<T> Clone for State<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for State<T> {}
impl<T> PartialEq for State<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> Eq for State<T> {}
impl<T> State<T> {
pub const STATE_BITS: u32 = <PtrState<T>>::STATE_BITS;
pub const STATE_MASK: usize = <PtrState<T>>::STATE_MASK;
#[must_use]
pub const fn zero() -> Self {
State(0, PhantomData)
}
#[inline]
#[must_use]
pub const fn value(&self) -> usize {
self.0
}
#[inline]
#[must_use]
pub const fn new(value: usize) -> Option<Self> {
if value & Self::STATE_MASK == value {
Some(State(value, PhantomData))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn new_truncated(value: usize) -> Self {
State(value & Self::STATE_MASK, PhantomData)
}
}
impl<T> From<State<T>> for usize {
#[inline]
fn from(state: State<T>) -> Self {
state.value()
}
}
#[repr(transparent)]
pub struct PtrState<T>(*mut T);
impl<T> Clone for PtrState<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for PtrState<T> {}
impl<T> PartialEq for PtrState<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> Eq for PtrState<T> {}
impl<T> PtrState<T> {
pub const STATE_BITS: u32 = align_of::<T>().trailing_zeros();
pub const STATE_MASK: usize = align_of::<T>() - 1;
pub const ADDR_MASK: usize = !Self::STATE_MASK;
#[must_use]
pub const fn null_zero() -> Self {
PtrState(null_mut())
}
#[inline]
#[must_use]
pub fn null_state(state: State<T>) -> Self {
PtrState::new(null_mut(), state)
}
#[inline]
pub fn new(ptr: *mut T, state: State<T>) -> Self {
PtrState(ptr.cast::<u8>().wrapping_add(state.0).cast())
}
#[inline]
pub fn new_ref(ptr: &T, state: State<T>) -> Self {
PtrState::new(from_ref(ptr).cast_mut(), state)
}
#[inline]
pub fn new_mut(ptr: &mut T, state: State<T>) -> Self {
PtrState::new(from_mut(ptr), state)
}
#[inline]
pub const fn new_zero(ptr: *mut T) -> Self {
PtrState(ptr)
}
#[inline]
pub const fn from_raw(ptr: *mut T) -> Self {
PtrState(ptr)
}
#[inline]
#[must_use]
pub const fn raw(&self) -> *mut T {
self.0
}
#[inline]
#[must_use]
pub fn with_state(&self, state: State<T>) -> Self {
PtrState::new(self.ptr(), state)
}
#[inline]
#[must_use]
pub fn with_ptr(&self, ptr: *mut T) -> Self {
PtrState::new(ptr, self.state())
}
#[must_use]
pub fn ptr(&self) -> *mut T {
let state = (self.0 as usize) & Self::STATE_MASK;
self.0.cast::<u8>().wrapping_sub(state).cast()
}
#[must_use]
pub fn state(&self) -> State<T> {
let state = (self.0 as usize) & Self::STATE_MASK;
State(state, PhantomData)
}
}
#[repr(transparent)]
pub struct AtomicPtrState<T>(AtomicPtr<T>);
impl<T> AtomicPtrState<T> {
pub const STATE_BITS: u32 = align_of::<T>().trailing_zeros();
pub const STATE_MASK: usize = align_of::<T>() - 1;
pub const ADDR_MASK: usize = !Self::STATE_MASK;
#[must_use]
pub const fn null_zero() -> Self {
AtomicPtrState(AtomicPtr::new(null_mut()))
}
#[inline]
#[must_use]
pub fn null_state(state: State<T>) -> Self {
AtomicPtrState::new(null_mut(), state)
}
#[inline]
pub fn new(ptr: *mut T, state: State<T>) -> Self {
AtomicPtrState(AtomicPtr::new(
ptr.cast::<u8>().wrapping_add(state.0).cast(),
))
}
#[inline]
pub fn new_ref(ptr: &T, state: State<T>) -> Self {
AtomicPtrState::new(from_ref(ptr).cast_mut(), state)
}
#[inline]
pub fn new_mut(ptr: &mut T, state: State<T>) -> Self {
AtomicPtrState::new(from_mut(ptr), state)
}
#[inline]
pub fn new_zero(ptr: *mut T) -> Self {
AtomicPtrState(AtomicPtr::new(ptr))
}
#[inline]
pub const fn from_raw(ptr: *mut T) -> Self {
AtomicPtrState(AtomicPtr::new(ptr))
}
#[inline]
#[must_use]
pub fn from_ptr_state(ptr_state: PtrState<T>) -> Self {
AtomicPtrState(AtomicPtr::new(ptr_state.raw()))
}
#[inline]
pub fn load(&self, order: Ordering) -> PtrState<T> {
PtrState(self.0.load(order))
}
#[inline]
pub fn store(&self, value: PtrState<T>, order: Ordering) {
self.0.store(value.0, order);
}
#[inline]
pub fn swap(&self, value: PtrState<T>, order: Ordering) -> PtrState<T> {
PtrState(self.0.swap(value.0, order))
}
#[allow(clippy::missing_errors_doc)]
#[inline]
pub fn compare_exchange(
&self,
current: PtrState<T>,
new: PtrState<T>,
success: Ordering,
failure: Ordering,
) -> Result<PtrState<T>, PtrState<T>> {
self.0
.compare_exchange(current.0, new.0, success, failure)
.map(PtrState)
.map_err(PtrState)
}
#[allow(clippy::missing_errors_doc)]
#[inline]
pub fn compare_exchange_weak(
&self,
current: PtrState<T>,
new: PtrState<T>,
success: Ordering,
failure: Ordering,
) -> Result<PtrState<T>, PtrState<T>> {
self.0
.compare_exchange_weak(current.0, new.0, success, failure)
.map(PtrState)
.map_err(PtrState)
}
}