ghost_gc/
gc_weak.rs

1use std::{marker::PhantomData, ptr::NonNull};
2
3use crate::{gc_box::GcBox, Collect, Gc, Invariant};
4
5pub struct Weak<'b, T: ?Sized>(NonNull<()>, Invariant<'b>, PhantomData<*const T>);
6
7impl<T: ?Sized> Default for Weak<'_, T> {
8    fn default() -> Self {
9        Weak(
10            NonNull::new(core::ptr::without_provenance_mut(usize::MAX)).unwrap(),
11            Invariant,
12            PhantomData,
13        )
14    }
15}
16
17impl<'b, T: ?Sized> Weak<'b, T> {
18    pub fn new() -> Weak<'b, T> {
19        Weak::default()
20    }
21
22    pub(crate) fn as_box(&self) -> Option<GcBox<T>> {
23        if self.0.addr().get() == usize::MAX {
24            None
25        } else {
26            // Safety: If the pointer isn't `usize::MAX`, it must be a pointer which came from
27            // `GcBox::into_raw`.
28            Some(unsafe { GcBox::from_raw(self.0) })
29        }
30    }
31
32    pub(crate) unsafe fn from_box(ptr: GcBox<T>) -> Weak<'b, T> {
33        Weak(ptr.into_raw(), Invariant, PhantomData)
34    }
35
36    pub fn upgrade(self) -> Option<Gc<'b, T>> {
37        if let Some(b) = self.as_box() {
38            if b.is_initialized() {
39                Some(unsafe { Gc::from_box(b) })
40            } else {
41                None
42            }
43        } else {
44            None
45        }
46    }
47}
48
49unsafe impl<T: ?Sized> Collect for Weak<'_, T> {
50    const NEEDS_TRACE: bool = true;
51
52    fn trace(&self, _c: &crate::Collector) {
53        use crate::gc_box::Colour;
54
55        if let Some(gc) = self.as_box() {
56            unsafe { gc.set_colour(Colour::Weak) };
57        }
58    }
59}