use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering::*;
pub(crate) use self::list::{LocalNode, Node};
use super::RefCnt;
mod fast;
mod helping;
mod list;
#[derive(Debug)]
pub(crate) struct Debt(pub(crate) AtomicUsize);
impl Debt {
pub(crate) const NONE: usize = 0b11;
}
impl Default for Debt {
fn default() -> Self {
Debt(AtomicUsize::new(Self::NONE))
}
}
impl Debt {
#[inline]
pub(crate) fn pay<T: RefCnt>(&self, ptr: *const T::Base) -> bool {
self.0
.compare_exchange(ptr as usize, Self::NONE, SeqCst, SeqCst)
.is_ok()
}
pub(crate) fn pay_all<T, R>(ptr: *const T::Base, storage_addr: usize, replacement: R)
where
T: RefCnt,
R: Fn() -> T,
{
LocalNode::with(|local| {
let val = unsafe { T::from_ptr(ptr) };
T::inc(&val);
Node::traverse::<(), _>(|node| {
let _reservation = node.reserve_writer();
local.help(node, storage_addr, &replacement);
let all_slots = node
.fast_slots()
.chain(core::iter::once(node.helping_slot()));
for slot in all_slots {
if slot.pay::<T>(ptr) {
T::inc(&val);
}
}
None
});
})
}
}
#[cfg(test)]
mod tests {
use alloc::sync::Arc;
#[test]
fn arc_zst() {
struct A;
struct B;
let a = Arc::new(A);
let b = Arc::new(B);
let aref: &A = &a;
let bref: &B = &b;
let aptr = aref as *const _ as usize;
let bptr = bref as *const _ as usize;
assert_ne!(aptr, bptr);
}
}