facet_reflect/wip/
heap_value.rs

1use crate::Peek;
2use crate::ReflectError;
3use crate::trace;
4use core::{alloc::Layout, marker::PhantomData};
5use facet_core::{Facet, PtrConst, PtrMut, Shape};
6#[cfg(feature = "log")]
7use owo_colors::OwoColorize as _;
8
9/// A type-erased value stored on the heap
10pub struct HeapValue<'a> {
11    pub(crate) guard: Option<Guard>,
12    pub(crate) shape: &'static Shape,
13    pub(crate) phantom: PhantomData<&'a ()>,
14}
15
16impl Drop for HeapValue<'_> {
17    fn drop(&mut self) {
18        if let Some(guard) = self.guard.take() {
19            if let Some(drop_fn) = self.shape.vtable.drop_in_place {
20                unsafe { drop_fn(PtrMut::new(guard.ptr)) };
21            }
22            drop(guard);
23        }
24    }
25}
26
27impl<'a> HeapValue<'a> {
28    /// Returns a peek that allows exploring the heap value.
29    pub fn peek(&self) -> Peek<'a> {
30        unsafe { Peek::unchecked_new(PtrConst::new(self.guard.as_ref().unwrap().ptr), self.shape) }
31    }
32
33    /// Turn this heapvalue into a concrete type
34    pub fn materialize<T: Facet + 'a>(mut self) -> Result<T, ReflectError> {
35        if self.shape != T::SHAPE {
36            return Err(ReflectError::WrongShape {
37                expected: self.shape,
38                actual: T::SHAPE,
39            });
40        }
41
42        let guard = self.guard.take().unwrap();
43        let data = PtrConst::new(guard.ptr);
44        let res = unsafe { data.read::<T>() };
45        drop(guard); // free memory (but don't drop in place)
46        Ok(res)
47    }
48}
49
50impl HeapValue<'_> {
51    /// Formats the value using its Display implementation, if available
52    pub fn fmt_display(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53        if let Some(display_fn) = self.shape.vtable.display {
54            unsafe { display_fn(PtrConst::new(self.guard.as_ref().unwrap().ptr), f) }
55        } else {
56            write!(f, "⟨{}⟩", self.shape)
57        }
58    }
59
60    /// Formats the value using its Debug implementation, if available
61    pub fn fmt_debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
62        if let Some(debug_fn) = self.shape.vtable.debug {
63            unsafe { debug_fn(PtrConst::new(self.guard.as_ref().unwrap().ptr), f) }
64        } else {
65            write!(f, "⟨{}⟩", self.shape)
66        }
67    }
68}
69
70impl core::fmt::Display for HeapValue<'_> {
71    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
72        self.fmt_display(f)
73    }
74}
75
76impl core::fmt::Debug for HeapValue<'_> {
77    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78        self.fmt_debug(f)
79    }
80}
81
82impl PartialEq for HeapValue<'_> {
83    fn eq(&self, other: &Self) -> bool {
84        if self.shape != other.shape {
85            return false;
86        }
87        if let Some(eq_fn) = self.shape.vtable.eq {
88            unsafe {
89                eq_fn(
90                    PtrConst::new(self.guard.as_ref().unwrap().ptr),
91                    PtrConst::new(other.guard.as_ref().unwrap().ptr),
92                )
93            }
94        } else {
95            false
96        }
97    }
98}
99
100impl PartialOrd for HeapValue<'_> {
101    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
102        if self.shape != other.shape {
103            return None;
104        }
105        if let Some(partial_ord_fn) = self.shape.vtable.partial_ord {
106            unsafe {
107                partial_ord_fn(
108                    PtrConst::new(self.guard.as_ref().unwrap().ptr),
109                    PtrConst::new(other.guard.as_ref().unwrap().ptr),
110                )
111            }
112        } else {
113            None
114        }
115    }
116}
117
118/// A guard structure to manage memory allocation and deallocation.
119///
120/// This struct holds a raw pointer to the allocated memory and the layout
121/// information used for allocation. It's responsible for deallocating
122/// the memory when dropped.
123pub struct Guard {
124    /// Raw pointer to the allocated memory.
125    pub(crate) ptr: *mut u8,
126    /// Layout information of the allocated memory.
127    pub(crate) layout: Layout,
128}
129
130impl Drop for Guard {
131    fn drop(&mut self) {
132        if self.layout.size() != 0 {
133            trace!(
134                "Deallocating memory at ptr: {:p}, size: {}, align: {}",
135                self.ptr.cyan(),
136                self.layout.size().yellow(),
137                self.layout.align().green()
138            );
139            // SAFETY: `ptr` has been allocated via the global allocator with the given layout
140            unsafe { alloc::alloc::dealloc(self.ptr, self.layout) };
141        }
142    }
143}