use core::cell::Cell;
use core::sync::atomic;
use core::sync::atomic::{AtomicUsize, Ordering};
use static_assertions::{assert_eq_align, assert_eq_size, assert_impl_all, assert_not_impl_any};
use crate::algorithm::abort;
use crate::{Algorithm, FlexRc, FlexRcInner};
assert_eq_size!(LocalMeta, SharedMeta);
assert_eq_align!(LocalMeta, SharedMeta);
assert_eq_size!(LocalInner<usize>, SharedInner<usize>);
assert_eq_align!(LocalInner<usize>, SharedInner<usize>);
assert_eq_size!(LocalRc<usize>, SharedRc<usize>);
assert_eq_align!(LocalRc<usize>, SharedRc<usize>);
assert_impl_all!(SharedRc<usize>: Send, Sync);
assert_not_impl_any!(LocalRc<usize>: Send, Sync);
const MAX_LOCAL_COUNT: usize = usize::MAX;
const MAX_SHARED_COUNT: usize = usize::MAX >> 1;
#[repr(C)]
pub struct LocalMeta {
count: Cell<usize>,
}
pub type LocalRc<T> = FlexRc<LocalMeta, SharedMeta, T>;
type LocalInner<T> = FlexRcInner<LocalMeta, SharedMeta, T>;
type SharedInner<T> = FlexRcInner<SharedMeta, LocalMeta, T>;
impl Algorithm<LocalMeta, SharedMeta> for LocalMeta {
#[inline]
fn create() -> Self {
Self {
count: Cell::new(1),
}
}
#[inline]
fn is_unique(&self) -> bool {
self.count.get() == 1
}
#[inline(always)]
fn clone(&self) {
let old = self.count.get();
if old == MAX_LOCAL_COUNT {
abort()
}
self.count.set(old + 1);
}
#[inline(always)]
fn drop(&self) -> bool {
self.count.set(self.count.get() - 1);
self.count.get() == 0
}
#[inline]
fn try_into_other<T: ?Sized>(
&self,
inner: *mut LocalInner<T>,
) -> Result<*mut SharedInner<T>, *mut LocalInner<T>> {
if self.is_unique() {
Ok(inner as *mut SharedInner<T>)
} else {
Err(inner)
}
}
#[inline]
fn try_to_other<T: ?Sized>(
&self,
inner: *mut LocalInner<T>,
) -> Result<*mut SharedInner<T>, *mut LocalInner<T>> {
Err(inner)
}
}
#[repr(C)]
pub struct SharedMeta {
count: AtomicUsize,
}
pub type SharedRc<T> = FlexRc<SharedMeta, LocalMeta, T>;
unsafe impl<T: Send + Sync> Send for SharedRc<T> {}
unsafe impl<T: Send + Sync> Sync for SharedRc<T> {}
impl Algorithm<SharedMeta, LocalMeta> for SharedMeta {
#[inline]
fn create() -> Self {
Self {
count: AtomicUsize::new(1),
}
}
#[inline]
fn is_unique(&self) -> bool {
self.count.load(Ordering::Acquire) == 1
}
#[inline(always)]
fn clone(&self) {
let old = self.count.fetch_add(1, Ordering::Relaxed);
if old > MAX_SHARED_COUNT {
abort()
}
}
#[inline(always)]
fn drop(&self) -> bool {
if self.count.fetch_sub(1, Ordering::Release) == 1 {
atomic::fence(Ordering::Acquire);
true
} else {
false
}
}
#[inline]
fn try_into_other<T: ?Sized>(
&self,
inner: *mut SharedInner<T>,
) -> Result<*mut LocalInner<T>, *mut SharedInner<T>> {
if self.is_unique() {
Ok(inner as *mut LocalInner<T>)
} else {
Err(inner)
}
}
#[inline]
fn try_to_other<T: ?Sized>(
&self,
inner: *mut SharedInner<T>,
) -> Result<*mut LocalInner<T>, *mut SharedInner<T>> {
Err(inner)
}
}