use core::ptr::NonNull;
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct WeakPtrData(u32);
impl WeakPtrData {
pub const EMPTY: Self = Self(0);
const REF_MASK: u32 = 0x7FFF_FFFF; const FINALIZED_BIT: u32 = 0x8000_0000;
#[inline]
pub fn reference_count(self) -> u32 {
self.0 & Self::REF_MASK
}
#[inline]
pub fn set_reference_count(&mut self, n: u32) {
debug_assert!(n <= Self::REF_MASK);
self.0 = (self.0 & Self::FINALIZED_BIT) | (n & Self::REF_MASK);
}
#[inline]
pub fn finalized(self) -> bool {
(self.0 & Self::FINALIZED_BIT) != 0
}
#[inline]
pub fn set_finalized(&mut self, v: bool) {
if v {
self.0 |= Self::FINALIZED_BIT;
} else {
self.0 &= !Self::FINALIZED_BIT;
}
}
pub fn on_finalize(&mut self) -> bool {
debug_assert!(!self.finalized());
self.set_finalized(true);
self.reference_count() == 0
}
}
pub trait HasWeakPtrData {
unsafe fn weak_ptr_data(this: *mut Self) -> *mut WeakPtrData;
}
pub struct WeakPtr<T: HasWeakPtrData> {
raw_ptr: Option<NonNull<T>>,
}
pub type Data = WeakPtrData;
impl<T: HasWeakPtrData> WeakPtr<T> {
pub const EMPTY: Self = Self { raw_ptr: None };
pub fn init_ref(req: &mut T) -> Self {
let d = unsafe { &mut *T::weak_ptr_data(req) };
debug_assert!(!d.finalized());
d.set_reference_count(d.reference_count() + 1);
Self {
raw_ptr: Some(NonNull::from(req)),
}
}
pub fn get(&mut self) -> Option<&mut T> {
if let Some(value) = self.raw_ptr {
unsafe {
if !(*T::weak_ptr_data(value.as_ptr())).finalized() {
return Some(&mut *value.as_ptr());
}
self.deref_internal(value);
}
}
None
}
unsafe fn deref_internal(&mut self, value: NonNull<T>) {
let weak_data = unsafe { &mut *T::weak_ptr_data(value.as_ptr()) };
self.raw_ptr = None;
let count = weak_data.reference_count() - 1;
weak_data.set_reference_count(count);
if weak_data.finalized() && count == 0 {
drop(unsafe { bun_core::heap::take(value.as_ptr()) });
}
}
}
impl<T: HasWeakPtrData> Drop for WeakPtr<T> {
fn drop(&mut self) {
if let Some(value) = self.raw_ptr {
unsafe { self.deref_internal(value) };
}
}
}
impl<T: HasWeakPtrData> Default for WeakPtr<T> {
fn default() -> Self {
Self::EMPTY
}
}