comet/
gcref.rs

1use std::{
2    collections::HashMap,
3    fmt::{self},
4    marker::PhantomData,
5    ops::{Deref, DerefMut},
6    ptr::NonNull,
7};
8
9use crate::{header::HeapObjectHeader, internal::{finalize_trait::FinalizeTrait, gc_info::{GCInfoIndex, GCInfoTrait}, trace_trait::TraceTrait}};
10/// A *typed* garbage collected pointer to a value.
11///
12/// This is the equivalent of a garbage collected smart-pointer.
13/// 
14/// The smart pointer is simply a guarantee to the garbage collector
15/// that this points to a garbage collected object with the correct header,
16/// and not some arbitrary bits that you've decided to heap allocate.
17#[repr(C)]
18pub struct GcRef<T> {
19    pub(crate) raw: UntypedGcRef,
20    pub(crate) marker: PhantomData<T>,
21}
22
23impl<T> GcRef<T> {
24    pub fn into_raw(self) -> *const HeapObjectHeader {
25        self.raw.header.as_ptr()
26    }
27    pub fn downcast(self) -> UntypedGcRef {
28        self.raw
29    }
30}
31
32impl<T> Deref for GcRef<T> {
33    type Target = T;
34    fn deref(&self) -> &Self::Target {
35        unsafe { &*self.raw.get().cast::<T>() }
36    }
37}
38impl<T> DerefMut for GcRef<T> {
39    fn deref_mut(&mut self) -> &mut Self::Target {
40        unsafe { &mut *self.raw.get().cast::<T>() }
41    }
42}
43
44/// A *untyped* garbage collected pointer to a value, you can think of it as `void*` pointer but managed by GC.
45///
46/// This is the equivalent of a garbage collected smart-pointer.
47/// 
48/// The smart pointer is simply a guarantee to the garbage collector
49/// that this points to a garbage collected object with the correct header,
50/// and not some arbitrary bits that you've decided to heap allocate.
51#[derive(Clone, Copy)]
52#[repr(C)]
53pub struct UntypedGcRef {
54    pub(crate) header: NonNull<HeapObjectHeader>,
55}
56
57impl UntypedGcRef {
58    /// Returns data part of GC object. That is part of allocation *after* heap object header. 
59    pub fn get(&self) -> *mut u8 {
60        unsafe { (*self.header.as_ptr()).payload() as _ }
61    }
62    /// Returns true if object has the same `index`. 
63    pub fn is(&self,index: GCInfoIndex) -> bool {
64        unsafe {
65            let header = &*self.header.as_ptr();
66            header.get_gc_info_index() == index
67        }
68    }
69    /// Returns Some(T) if `T::index()` is the same as in this object. 
70    pub fn cast<T: GCInfoTrait<T> + TraceTrait + FinalizeTrait<T> + 'static>(
71        self,
72    ) -> Option<GcRef<T>> {
73        unsafe {
74            let header = &*self.header.as_ptr();
75            if header.get_gc_info_index() == T::index() {
76                return Some(GcRef {
77                    raw: self,
78                    marker: PhantomData,
79                });
80            } else {
81                None
82            }
83        }
84    }
85    /// Unchecked cast withouth verifying indexes. 
86    pub unsafe fn cast_unchecked<T: GCInfoTrait<T> + TraceTrait + FinalizeTrait<T> + 'static>(
87        self,
88    ) -> GcRef<T> {
89        self.cast::<T>()
90            .unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() })
91    }
92}
93
94impl fmt::Debug for UntypedGcRef {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        write!(f, "UntypedGcRef({:p})", self.header)
97    }
98}
99impl fmt::Pointer for UntypedGcRef {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        write!(f, "UntypedGcRef({:p})", self.header)
102    }
103}
104impl<T> std::fmt::Pointer for GcRef<T> {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        write!(f, "{:p}", self.raw)
107    }
108}
109
110impl<T: std::fmt::Debug> std::fmt::Debug for GcRef<T> {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        write!(f, "{:?}", **self)
113    }
114}
115impl<T: std::fmt::Display> std::fmt::Display for GcRef<T> {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        write!(f, "{}", **self)
118    }
119}
120pub struct WeakSlot {
121    pub(crate) value: Option<UntypedGcRef>,
122}
123
124impl FinalizeTrait<WeakSlot> for WeakSlot {}
125impl TraceTrait for WeakSlot {}
126
127
128/// Weak GC reference. Has almost the same semantics as [std::rc::Weak]
129#[repr(transparent)]
130#[derive(Clone, Copy)]
131pub struct WeakGcRef {
132    pub(crate) slot: GcRef<WeakSlot>,
133}
134
135impl WeakGcRef {
136    pub fn upgrade(&self) -> Option<UntypedGcRef> {
137        self.slot.value
138    }
139
140    pub fn slot(self) -> GcRef<WeakSlot> {
141        self.slot
142    }
143}
144impl<T> Copy for GcRef<T> {}
145
146impl<T> Clone for GcRef<T> {
147    fn clone(&self) -> Self {
148        *self
149    }
150}
151
152impl<T: TraceTrait> TraceTrait for GcRef<T> {
153    fn trace(&self, vis: &mut crate::visitor::Visitor) {
154        vis.trace_gcref(*self);
155    }
156}
157
158impl TraceTrait for UntypedGcRef {
159    fn trace(&self, vis: &mut crate::visitor::Visitor) {
160        vis.trace_untyped(*self);
161    }
162}
163
164macro_rules! impl_prim {
165    ($($t:ty)*) => {
166        $(
167            impl FinalizeTrait<$t> for $t {
168
169            }
170            impl TraceTrait for $t {}
171        )*
172    };
173}
174
175impl_prim! (
176    bool f32 f64
177    u8 u16 u32 u64 u128 usize
178    i8 i16 i32 i64 i128 isize
179    String std::fs::File
180    std::path::PathBuf
181);
182
183impl<T> FinalizeTrait<Vec<T>> for Vec<T> {}
184impl<T: TraceTrait> TraceTrait for Vec<T> {
185    fn trace(&self, vis: &mut crate::visitor::Visitor) {
186        for elem in self.iter() {
187            vis.trace_ref(elem);
188        }
189    }
190}
191
192impl<K, V> FinalizeTrait<HashMap<K, V>> for HashMap<K, V> {}
193impl<K: TraceTrait, V: TraceTrait> TraceTrait for HashMap<K, V> {
194    fn trace(&self, vis: &mut crate::visitor::Visitor) {
195        for (k, v) in self.iter() {
196            k.trace(vis);
197            v.trace(vis);
198        }
199    }
200}
201
202impl<T> FinalizeTrait<Option<T>> for Option<T> {}
203
204impl<T: TraceTrait> TraceTrait for Option<T> {
205    fn trace(&self, vis: &mut crate::visitor::Visitor) {
206        match self {
207            Some(elem) => vis.trace_ref(elem),
208            _ => (),
209        }
210    }
211}
212
213impl<T, E> FinalizeTrait<Result<T, E>> for Result<T, E> {}
214impl<T: TraceTrait, E: TraceTrait> TraceTrait for Result<T, E> {
215    fn trace(&self, vis: &mut crate::visitor::Visitor) {
216        match self {
217            Ok(x) => x.trace(vis),
218            Err(x) => x.trace(vis),
219        }
220    }
221}
222
223impl PartialEq for UntypedGcRef {
224    fn eq(&self, other: &Self) -> bool {
225        self.header == other.header
226    }
227}
228
229impl Eq for UntypedGcRef {}
230
231impl<T> PartialEq for GcRef<T> {
232    fn eq(&self, other: &Self) -> bool {
233        self.raw == other.raw
234    }
235}
236
237impl<T> Eq for GcRef<T> {}