use std::{cell, pin, process, ptr};
#[repr(transparent)]
pub struct LocalRefCount(cell::Cell<u32>);
impl LocalRefCount {
pub const fn empty() -> Self {
Self(cell::Cell::new(0))
}
pub const fn one() -> Self {
Self(cell::Cell::new(1))
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.get() == 0
}
#[inline]
pub fn is_unique(&self) -> bool {
self.0.get() == 1
}
#[inline]
pub fn activate(&self) {
if !self.try_activate() {
process::abort();
}
}
#[inline]
pub fn try_activate(&self) -> bool {
if !self.is_empty() {
return false;
}
self.0.set(1);
true
}
#[inline]
pub fn deactivate(&self) {
if !self.try_deactivate() {
process::abort();
}
}
#[inline]
pub fn try_deactivate(&self) -> bool {
if !self.is_unique() {
return false;
}
self.0.set(0);
true
}
#[inline]
pub fn retain(&self) {
if !self.try_retain() {
process::abort();
}
}
#[inline]
pub fn try_retain(&self) -> bool {
let current = self.0.get();
let Some(next) = current.checked_add(1) else {
return false;
};
if current == 0 {
return false;
}
self.0.set(next);
true
}
#[must_use]
#[inline]
pub fn release(&self) -> bool {
let Some(last) = self.try_release() else {
process::abort();
};
last
}
#[must_use]
#[inline]
pub fn try_release(&self) -> Option<bool> {
let current = self.0.get();
if current == 0 {
return None;
}
if current == 1 {
return Some(true);
}
self.0.set(current - 1);
Some(false)
}
}
const _: () = assert!(size_of::<LocalRefCount>() == size_of::<u32>());
#[repr(transparent)]
pub struct StableLink<T> {
pointer: ptr::NonNull<T>,
}
pub unsafe trait StableLinkSource<T> {
fn pointer(self) -> ptr::NonNull<T>;
}
impl<T> StableLink<T> {
pub fn from_stable(source: impl StableLinkSource<T>) -> Self {
Self {
pointer: source.pointer(),
}
}
#[inline]
pub fn get(&self) -> pin::Pin<&T> {
unsafe { pin::Pin::new_unchecked(self.pointer.as_ref()) }
}
}
impl<T> Clone for StableLink<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for StableLink<T> {}
impl<T> PartialEq for StableLink<T> {
fn eq(&self, other: &Self) -> bool {
self.pointer == other.pointer
}
}
impl<T> Eq for StableLink<T> {}
#[repr(C)]
pub struct Checked<T> {
value: cell::UnsafeCell<T>,
active: cell::Cell<bool>,
thread: crate::ThreadBound,
}
impl<T> Checked<T> {
pub const fn new(value: T) -> Self {
Self {
value: cell::UnsafeCell::new(value),
active: cell::Cell::new(false),
thread: crate::ThreadBound::NEW,
}
}
pub fn with_mut<R>(&self, operation: impl for<'a> FnOnce(&'a mut T) -> R) -> R {
assert!(!self.active.replace(true), "reentrant checked cell access");
let access = Access(&self.active);
let result = operation(unsafe { &mut *self.value.get() });
drop(access);
result
}
}
struct Access<'a>(&'a cell::Cell<bool>);
impl Drop for Access<'_> {
fn drop(&mut self) {
self.0.set(false);
}
}