use crate::Peek;
use crate::ShapeMismatchError;
use crate::trace;
use core::ptr::NonNull;
use core::{alloc::Layout, marker::PhantomData};
use facet_core::{Facet, PtrConst, PtrMut, Shape};
pub struct HeapValue<'facet, const BORROW: bool = true> {
pub(crate) guard: Option<Guard>,
pub(crate) shape: &'static Shape,
pub(crate) phantom: PhantomData<&'facet ()>,
}
impl<'facet, const BORROW: bool> Drop for HeapValue<'facet, BORROW> {
fn drop(&mut self) {
if let Some(guard) = self.guard.take() {
unsafe {
self.shape
.call_drop_in_place(PtrMut::new(guard.ptr.as_ptr()));
}
drop(guard);
}
}
}
impl<'facet, const BORROW: bool> HeapValue<'facet, BORROW> {
pub fn peek(&self) -> Peek<'_, 'facet> {
unsafe {
Peek::unchecked_new(
PtrConst::new(self.guard.as_ref().unwrap().ptr.as_ptr()),
self.shape,
)
}
}
pub const fn shape(&self) -> &'static Shape {
self.shape
}
pub fn materialize<T: Facet<'facet>>(mut self) -> Result<T, ShapeMismatchError> {
trace!(
"HeapValue::materialize: Materializing heap value with shape {} to type {}",
self.shape,
T::SHAPE
);
if self.shape != T::SHAPE {
trace!(
"HeapValue::materialize: Shape mismatch! Expected {}, but heap value has {}",
T::SHAPE,
self.shape
);
return Err(ShapeMismatchError {
expected: T::SHAPE,
actual: self.shape,
});
}
trace!("HeapValue::materialize: Shapes match, proceeding with materialization");
let guard = self.guard.take().unwrap();
let data = PtrConst::new(guard.ptr.as_ptr());
let res = unsafe { data.read::<T>() };
drop(guard); trace!("HeapValue::materialize: Successfully materialized value");
Ok(res)
}
}
impl<'facet, const BORROW: bool> HeapValue<'facet, BORROW> {
pub fn fmt_display(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let ptr = PtrConst::new(self.guard.as_ref().unwrap().ptr.as_ptr());
if let Some(result) = unsafe { self.shape.call_display(ptr, f) } {
return result;
}
write!(f, "⟨{}⟩", self.shape)
}
pub fn fmt_debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let ptr = PtrConst::new(self.guard.as_ref().unwrap().ptr.as_ptr());
if let Some(result) = unsafe { self.shape.call_debug(ptr, f) } {
return result;
}
write!(f, "⟨{}⟩", self.shape)
}
}
impl<'facet, const BORROW: bool> core::fmt::Display for HeapValue<'facet, BORROW> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.fmt_display(f)
}
}
impl<'facet, const BORROW: bool> core::fmt::Debug for HeapValue<'facet, BORROW> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.fmt_debug(f)
}
}
impl<'facet, const BORROW: bool> PartialEq for HeapValue<'facet, BORROW> {
fn eq(&self, other: &Self) -> bool {
if self.shape != other.shape {
return false;
}
let self_ptr = PtrConst::new(self.guard.as_ref().unwrap().ptr.as_ptr());
let other_ptr = PtrConst::new(other.guard.as_ref().unwrap().ptr.as_ptr());
unsafe { self.shape.call_partial_eq(self_ptr, other_ptr) }.unwrap_or(false)
}
}
impl<'facet, const BORROW: bool> PartialOrd for HeapValue<'facet, BORROW> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
if self.shape != other.shape {
return None;
}
let self_ptr = PtrConst::new(self.guard.as_ref().unwrap().ptr.as_ptr());
let other_ptr = PtrConst::new(other.guard.as_ref().unwrap().ptr.as_ptr());
unsafe { self.shape.call_partial_cmp(self_ptr, other_ptr) }.flatten()
}
}
pub struct Guard {
pub(crate) ptr: NonNull<u8>,
pub(crate) layout: Layout,
pub(crate) should_dealloc: bool,
}
impl Drop for Guard {
fn drop(&mut self) {
if self.should_dealloc && self.layout.size() != 0 {
trace!(
"Deallocating memory at ptr: {:p}, size: {}, align: {}",
self.ptr,
self.layout.size(),
self.layout.align()
);
unsafe { alloc::alloc::dealloc(self.ptr.as_ptr(), self.layout) };
}
}
}
impl<'facet, const BORROW: bool> HeapValue<'facet, BORROW> {
pub const unsafe fn as_ref<T>(&self) -> &T {
unsafe { &*(self.guard.as_ref().unwrap().ptr.as_ptr() as *const T) }
}
}