use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::sync::atomic::{AtomicUsize, Ordering};
use super::AtomicRefCell;
const MUT_BIT: usize = !(usize::MAX >> 1);
impl<T: ?Sized> AtomicRefCell<T> {
#[inline]
fn ptr(&self) -> NonNull<T> {
unsafe { NonNull::new_unchecked(self.data.get()) }
}
}
struct BorrowToken<'a>(&'a AtomicUsize);
impl<'a> BorrowToken<'a> {
#[inline]
fn borrow(counter: &'a AtomicUsize) -> Option<Self> {
let mut prev_counter = counter.load(Ordering::Relaxed);
let success = loop {
if prev_counter & MUT_BIT != 0 {
break false;
}
let next_counter = prev_counter + 1;
if next_counter & MUT_BIT != 0 {
break false;
}
match counter.compare_exchange_weak(
prev_counter,
next_counter,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => break true,
Err(counter) => {
prev_counter = counter;
}
}
};
success.then(|| Self(counter))
}
}
impl Clone for BorrowToken<'_> {
#[inline]
fn clone(&self) -> Self {
Self::borrow(self.0).unwrap()
}
}
impl Drop for BorrowToken<'_> {
#[inline]
fn drop(&mut self) {
self.0.fetch_sub(1, Ordering::Release);
}
}
struct BorrowTokenMut<'a>(&'a AtomicUsize);
impl<'a> BorrowTokenMut<'a> {
#[inline]
fn borrow_mut(counter: &'a AtomicUsize) -> Option<Self> {
let success = counter
.compare_exchange(0, MUT_BIT, Ordering::Acquire, Ordering::Relaxed)
.is_ok();
success.then(|| Self(counter))
}
}
impl Drop for BorrowTokenMut<'_> {
#[inline]
fn drop(&mut self) {
self.0.store(0, Ordering::Release);
}
}
pub struct AtomicRef<'a, T: ?Sized> {
ptr: NonNull<T>,
token: BorrowToken<'a>,
}
unsafe impl<'a, T: ?Sized> Send for AtomicRef<'a, T> where for<'r> &'r T: Send {}
unsafe impl<'a, T: ?Sized> Sync for AtomicRef<'a, T> where for<'r> &'r T: Sync {}
impl<'a, T: ?Sized> AtomicRef<'a, T> {
#[inline]
pub(super) fn new(cell: &'a AtomicRefCell<T>) -> Option<Self> {
let token = BorrowToken::borrow(&cell.counter)?;
Some(Self {
ptr: cell.ptr(),
token,
})
}
#[inline]
pub fn map<U: ?Sized>(orig: Self, f: impl FnOnce(&T) -> &U) -> AtomicRef<'a, U> {
AtomicRef {
ptr: NonNull::from_ref(f(&*orig)),
token: orig.token,
}
}
#[expect(clippy::should_implement_trait)]
#[inline]
pub fn clone(orig: &Self) -> Self {
Self {
ptr: orig.ptr,
token: orig.token.clone(),
}
}
}
impl<T: ?Sized> Deref for AtomicRef<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for AtomicRef<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("AtomicRef").field(&**self).finish()
}
}
pub struct AtomicRefMut<'a, T: ?Sized> {
ptr: NonNull<T>,
token: BorrowTokenMut<'a>,
_phantom: PhantomData<&'a mut T>,
}
unsafe impl<'a, T: ?Sized> Send for AtomicRefMut<'a, T> where for<'r> &'r mut T: Send {}
unsafe impl<'a, T: ?Sized> Sync for AtomicRefMut<'a, T> where for<'r> &'r mut T: Sync {}
impl<'a, T: ?Sized> AtomicRefMut<'a, T> {
#[inline]
pub(super) fn new(cell: &'a AtomicRefCell<T>) -> Option<Self> {
let token = BorrowTokenMut::borrow_mut(&cell.counter)?;
Some(Self {
ptr: cell.ptr(),
token,
_phantom: PhantomData,
})
}
#[inline]
pub fn map<U: ?Sized>(mut orig: Self, f: impl FnOnce(&mut T) -> &mut U) -> AtomicRefMut<'a, U> {
AtomicRefMut {
ptr: NonNull::from_mut(f(&mut *orig)),
token: orig.token,
_phantom: PhantomData,
}
}
}
impl<T: ?Sized> Deref for AtomicRefMut<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}
impl<T: ?Sized> DerefMut for AtomicRefMut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.ptr.as_mut() }
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for AtomicRefMut<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("AtomicRefMut").field(&**self).finish()
}
}