use std::{
ops::{Deref, DerefMut},
ptr::NonNull,
sync::atomic::{AtomicU32, Ordering},
};
use fromsoftware_shared_stl::StlAllocator;
use vtable_rs::VPtr;
use crate::dlkr::DLAllocator;
#[repr(transparent)]
pub struct DLReferencePointer<T: DLReferenceCountObject>(NonNull<T>);
impl<T: DLReferenceCountObject> DLReferencePointer<T> {
pub fn new(allocator: &'static DLAllocator, data: T) -> Self {
let new = allocator.allocate::<T>();
unsafe { new.write(data) }
Self(new)
}
}
impl<T: DLReferenceCountObject> Deref for DLReferencePointer<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.0.as_ref() }
}
}
impl<T: DLReferenceCountObject> DerefMut for DLReferencePointer<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}
impl<T: DLReferenceCountObject> Clone for DLReferencePointer<T> {
fn clone(&self) -> Self {
self.reference_count().fetch_add(1, Ordering::Relaxed);
Self(self.0)
}
}
impl<T: DLReferenceCountObject> Drop for DLReferencePointer<T> {
fn drop(&mut self) {
if self.reference_count().fetch_sub(1, Ordering::Relaxed) == 1 {
(self.vtable().destroy)(self);
}
}
}
#[vtable_rs::vtable]
pub trait DLReferenceCountObjectVmt {
fn destroy(&mut self);
fn destructor(&mut self);
}
pub trait DLReferenceCountObject: Sized + 'static {
fn vtable(&self) -> VPtr<dyn DLReferenceCountObjectVmt, Self>;
fn reference_count(&self) -> &AtomicU32;
}