use std::alloc::{Layout, handle_alloc_error};
use std::ops::{Deref, DerefMut};
use std::{fmt, marker::PhantomData, ptr::NonNull};
use crate::{GameAllocator, NoOpAllocator};
#[repr(transparent)]
pub struct OwnedPtr<T, A: GameAllocator = NoOpAllocator> {
ptr: NonNull<T>,
_marker: PhantomData<A>,
}
impl<T, A: GameAllocator> OwnedPtr<T, A> {
pub fn new(value: T) -> Self {
let layout = Layout::new::<T>();
if layout.size() == 0 {
OwnedPtr {
ptr: NonNull::dangling(),
_marker: Default::default(),
}
} else if let Ok(ptr) = A::allocate(layout) {
let ptr = ptr.cast::<T>();
unsafe { ptr.write(value) };
OwnedPtr {
ptr,
_marker: Default::default(),
}
} else {
handle_alloc_error(layout)
}
}
pub fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
}
impl<T: Default, A: GameAllocator> Default for OwnedPtr<T, A> {
fn default() -> Self {
OwnedPtr::new(Default::default())
}
}
impl<T, A: GameAllocator> Deref for OwnedPtr<T, A> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref() }
}
}
impl<T, A: GameAllocator> AsRef<T> for OwnedPtr<T, A> {
fn as_ref(&self) -> &T {
self.deref()
}
}
impl<T, A: GameAllocator> DerefMut for OwnedPtr<T, A> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut() }
}
}
impl<T, A: GameAllocator> AsMut<T> for OwnedPtr<T, A> {
fn as_mut(&mut self) -> &mut T {
self.deref_mut()
}
}
impl<T, A: GameAllocator> fmt::Debug for OwnedPtr<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.ptr.fmt(f)
}
}
impl<T, A: GameAllocator> fmt::Pointer for OwnedPtr<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
fmt::Pointer::fmt(&self.ptr, f)
}
}
impl<T, A: GameAllocator> Drop for OwnedPtr<T, A> {
fn drop(&mut self) {
unsafe {
self.ptr.drop_in_place();
if Layout::new::<T>().size() > 0 {
A::deallocate(self.ptr.cast::<u8>(), Layout::new::<T>());
}
}
}
}
unsafe impl<T: Send, A: GameAllocator + Send> Send for OwnedPtr<T, A> {}
unsafe impl<T: Sync, A: GameAllocator + Sync> Sync for OwnedPtr<T, A> where T: Sync {}