use core::sync::atomic::{AtomicU32, Ordering};
#[cfg(debug_assertions)]
use bun_core::ThreadLock;
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum ThreadSafety {
SingleThreaded,
ThreadSafe,
}
#[derive(PartialEq, Eq)]
pub enum DecrementResult {
KeepAlive,
ShouldDestroy,
}
pub struct RawRefCount {
raw_value: u32,
#[cfg(debug_assertions)]
thread_lock: ThreadLock,
}
impl RawRefCount {
pub fn init(initial_count: u32) -> Self {
Self {
raw_value: initial_count,
#[cfg(debug_assertions)]
thread_lock: ThreadLock::init_locked_if_non_comptime(),
}
}
pub fn increment(&mut self) {
#[cfg(debug_assertions)]
self.thread_lock.lock_or_assert();
self.raw_value += 1;
}
pub fn decrement(&mut self) -> DecrementResult {
#[cfg(debug_assertions)]
self.thread_lock.lock_or_assert();
self.raw_value -= 1;
if self.raw_value == 0 {
DecrementResult::ShouldDestroy
} else {
DecrementResult::KeepAlive
}
}
pub fn unsafe_get_value(&self) -> u32 {
self.raw_value
}
}
#[repr(transparent)]
pub struct RawAtomicRefCount {
raw_value: AtomicU32,
}
impl RawAtomicRefCount {
pub const fn init(initial_count: u32) -> Self {
Self {
raw_value: AtomicU32::new(initial_count),
}
}
pub fn increment(&self) {
let old = self.raw_value.fetch_add(1, Ordering::Relaxed); debug_assert!(old != u32::MAX, "overflow of thread-safe ref count");
}
pub fn decrement(&self) -> DecrementResult {
let old = self.raw_value.fetch_sub(1, Ordering::Release);
if cfg!(debug_assertions) || cfg!(windows) {
assert!(old != 0, "underflow of thread-safe ref count");
}
if old == 1 {
core::sync::atomic::fence(Ordering::Acquire);
DecrementResult::ShouldDestroy
} else {
DecrementResult::KeepAlive
}
}
pub fn unsafe_get_value(&self) -> u32 {
self.raw_value.load(Ordering::Acquire)
}
}