comet-gc 0.1.3

Garbage collection library for implementing VMs in Rust
Documentation
use std::{
    collections::HashMap,
    fmt::{self},
    marker::PhantomData,
    ops::{Deref, DerefMut},
    ptr::NonNull,
};

use crate::{header::HeapObjectHeader, internal::{finalize_trait::FinalizeTrait, gc_info::{GCInfoIndex, GCInfoTrait}, trace_trait::TraceTrait}};
/// A *typed* garbage collected pointer to a value.
///
/// This is the equivalent of a garbage collected smart-pointer.
/// 
/// The smart pointer is simply a guarantee to the garbage collector
/// that this points to a garbage collected object with the correct header,
/// and not some arbitrary bits that you've decided to heap allocate.
#[repr(C)]
pub struct GcRef<T> {
    pub(crate) raw: UntypedGcRef,
    pub(crate) marker: PhantomData<T>,
}

impl<T> GcRef<T> {
    pub fn into_raw(self) -> *const HeapObjectHeader {
        self.raw.header.as_ptr()
    }
    pub fn downcast(self) -> UntypedGcRef {
        self.raw
    }
}

impl<T> Deref for GcRef<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.raw.get().cast::<T>() }
    }
}
impl<T> DerefMut for GcRef<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *self.raw.get().cast::<T>() }
    }
}

/// A *untyped* garbage collected pointer to a value, you can think of it as `void*` pointer but managed by GC.
///
/// This is the equivalent of a garbage collected smart-pointer.
/// 
/// The smart pointer is simply a guarantee to the garbage collector
/// that this points to a garbage collected object with the correct header,
/// and not some arbitrary bits that you've decided to heap allocate.
#[derive(Clone, Copy)]
#[repr(C)]
pub struct UntypedGcRef {
    pub(crate) header: NonNull<HeapObjectHeader>,
}

impl UntypedGcRef {
    /// Returns data part of GC object. That is part of allocation *after* heap object header. 
    pub fn get(&self) -> *mut u8 {
        unsafe { (*self.header.as_ptr()).payload() as _ }
    }
    /// Returns true if object has the same `index`. 
    pub fn is(&self,index: GCInfoIndex) -> bool {
        unsafe {
            let header = &*self.header.as_ptr();
            header.get_gc_info_index() == index
        }
    }
    /// Returns Some(T) if `T::index()` is the same as in this object. 
    pub fn cast<T: GCInfoTrait<T> + TraceTrait + FinalizeTrait<T> + 'static>(
        self,
    ) -> Option<GcRef<T>> {
        unsafe {
            let header = &*self.header.as_ptr();
            if header.get_gc_info_index() == T::index() {
                return Some(GcRef {
                    raw: self,
                    marker: PhantomData,
                });
            } else {
                None
            }
        }
    }
    /// Unchecked cast withouth verifying indexes. 
    pub unsafe fn cast_unchecked<T: GCInfoTrait<T> + TraceTrait + FinalizeTrait<T> + 'static>(
        self,
    ) -> GcRef<T> {
        self.cast::<T>()
            .unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() })
    }
}

impl fmt::Debug for UntypedGcRef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "UntypedGcRef({:p})", self.header)
    }
}
impl fmt::Pointer for UntypedGcRef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "UntypedGcRef({:p})", self.header)
    }
}
impl<T> std::fmt::Pointer for GcRef<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:p}", self.raw)
    }
}

impl<T: std::fmt::Debug> std::fmt::Debug for GcRef<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", **self)
    }
}
impl<T: std::fmt::Display> std::fmt::Display for GcRef<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", **self)
    }
}
pub struct WeakSlot {
    pub(crate) value: Option<UntypedGcRef>,
}

impl FinalizeTrait<WeakSlot> for WeakSlot {}
impl TraceTrait for WeakSlot {}


/// Weak GC reference. Has almost the same semantics as [std::rc::Weak]
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct WeakGcRef {
    pub(crate) slot: GcRef<WeakSlot>,
}

impl WeakGcRef {
    pub fn upgrade(&self) -> Option<UntypedGcRef> {
        self.slot.value
    }

    pub fn slot(self) -> GcRef<WeakSlot> {
        self.slot
    }
}
impl<T> Copy for GcRef<T> {}

impl<T> Clone for GcRef<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T: TraceTrait> TraceTrait for GcRef<T> {
    fn trace(&self, vis: &mut crate::visitor::Visitor) {
        vis.trace_gcref(*self);
    }
}

impl TraceTrait for UntypedGcRef {
    fn trace(&self, vis: &mut crate::visitor::Visitor) {
        vis.trace_untyped(*self);
    }
}

macro_rules! impl_prim {
    ($($t:ty)*) => {
        $(
            impl FinalizeTrait<$t> for $t {

            }
            impl TraceTrait for $t {}
        )*
    };
}

impl_prim! (
    bool f32 f64
    u8 u16 u32 u64 u128 usize
    i8 i16 i32 i64 i128 isize
    String std::fs::File
    std::path::PathBuf
);

impl<T> FinalizeTrait<Vec<T>> for Vec<T> {}
impl<T: TraceTrait> TraceTrait for Vec<T> {
    fn trace(&self, vis: &mut crate::visitor::Visitor) {
        for elem in self.iter() {
            vis.trace_ref(elem);
        }
    }
}

impl<K, V> FinalizeTrait<HashMap<K, V>> for HashMap<K, V> {}
impl<K: TraceTrait, V: TraceTrait> TraceTrait for HashMap<K, V> {
    fn trace(&self, vis: &mut crate::visitor::Visitor) {
        for (k, v) in self.iter() {
            k.trace(vis);
            v.trace(vis);
        }
    }
}

impl<T> FinalizeTrait<Option<T>> for Option<T> {}

impl<T: TraceTrait> TraceTrait for Option<T> {
    fn trace(&self, vis: &mut crate::visitor::Visitor) {
        match self {
            Some(elem) => vis.trace_ref(elem),
            _ => (),
        }
    }
}

impl<T, E> FinalizeTrait<Result<T, E>> for Result<T, E> {}
impl<T: TraceTrait, E: TraceTrait> TraceTrait for Result<T, E> {
    fn trace(&self, vis: &mut crate::visitor::Visitor) {
        match self {
            Ok(x) => x.trace(vis),
            Err(x) => x.trace(vis),
        }
    }
}

impl PartialEq for UntypedGcRef {
    fn eq(&self, other: &Self) -> bool {
        self.header == other.header
    }
}

impl Eq for UntypedGcRef {}

impl<T> PartialEq for GcRef<T> {
    fn eq(&self, other: &Self) -> bool {
        self.raw == other.raw
    }
}

impl<T> Eq for GcRef<T> {}