use super::Instance;
use std::alloc::Layout;
use std::ptr::{self, NonNull};
use std::sync::{atomic, Arc};
#[derive(Debug)]
#[repr(C)]
pub struct InstanceRef {
strong: Arc<atomic::AtomicUsize>,
instance_layout: Layout,
instance: NonNull<Instance>,
}
impl InstanceRef {
pub(super) unsafe fn new(instance: NonNull<Instance>, instance_layout: Layout) -> Self {
Self {
strong: Arc::new(atomic::AtomicUsize::new(1)),
instance_layout,
instance,
}
}
const MAX_REFCOUNT: usize = std::usize::MAX - 1;
unsafe fn deallocate_instance(&mut self) {
let instance_ptr = self.instance.as_ptr();
ptr::drop_in_place(instance_ptr);
std::alloc::dealloc(instance_ptr as *mut u8, self.instance_layout);
}
pub fn strong_count(&self) -> usize {
self.strong.load(atomic::Ordering::SeqCst)
}
#[inline]
pub(crate) fn as_ref(&self) -> &Instance {
unsafe { self.instance.as_ref() }
}
#[inline]
pub(super) unsafe fn as_mut(&mut self) -> &mut Instance {
self.instance.as_mut()
}
}
unsafe impl Send for InstanceRef {}
unsafe impl Sync for InstanceRef {}
impl Clone for InstanceRef {
#[inline]
fn clone(&self) -> Self {
let old_size = self.strong.fetch_add(1, atomic::Ordering::Relaxed);
if old_size > Self::MAX_REFCOUNT {
panic!("Too many references of `InstanceRef`");
}
Self {
strong: self.strong.clone(),
instance_layout: self.instance_layout,
instance: self.instance.clone(),
}
}
}
impl PartialEq for InstanceRef {
fn eq(&self, other: &Self) -> bool {
self.instance == other.instance
}
}
impl Drop for InstanceRef {
fn drop(&mut self) {
if self.strong.fetch_sub(1, atomic::Ordering::Release) != 1 {
return;
}
atomic::fence(atomic::Ordering::Acquire);
unsafe { Self::deallocate_instance(self) };
}
}