mjb_gc 0.2.0

Garbage collected pointers with immediate dropping
Documentation
use alloc::{boxed::Box, vec::Vec};
use core::{
    cell::RefCell,
    num::{
        NonZeroI128,
        NonZeroI16,
        NonZeroI32,
        NonZeroI64,
        NonZeroI8,
        NonZeroIsize,
        NonZeroU128,
        NonZeroU16,
        NonZeroU32,
        NonZeroU64,
        NonZeroU8,
        NonZeroUsize,
    },
};

use crate::Trace;

macro_rules! impl_empty_trace {
    ($($t:ty),* $(,)*) => {
        $(
            unsafe impl Trace for $t {
                $crate::unsafe_empty_trace!{}
            }
        )*
    };
}

impl_empty_trace! {
    i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64,
    bool, (), NonZeroI8, NonZeroU8, NonZeroI16, NonZeroU16, NonZeroI32,
    NonZeroU32, NonZeroI64, NonZeroU64, NonZeroI128, NonZeroU128, NonZeroIsize,
    NonZeroUsize,
}

macro_rules! impl_tuple_trace {
    ($(($($t:ident),*),)*) => {
        $(
            #[allow(non_snake_case)]
            unsafe impl<$($t: Trace),*> Trace for ($($t,)*) {
                unsafe fn untrace(&self) {
                    match *self {
                        ($(ref $t,)*) => {
                            $(
                                unsafe { $t.untrace() };
                            )*
                        }
                    }
                }

                unsafe fn trace(&self) {
                    match *self {
                        ($(ref $t,)*) => {
                            $(
                                unsafe { $t.trace() };
                            )*
                        }
                    }
                }

                unsafe fn set_undone(&self) {
                    match *self {
                        ($(ref $t,)*) => {
                            $(
                                unsafe { $t.set_undone() };
                            )*
                        }
                    }
                }

                fn counts_match(&self) -> bool {
                    match *self {
                        ($(ref $t,)*) => {
                            true $(& $t.counts_match())*
                        }
                    }
                }

                fn could_contain_cycles() -> bool {
                    false $(|| <$t>::could_contain_cycles())*
                }
            }
        )*
    }
}

impl_tuple_trace! {
    (A),
    (A, B),
    (A, B, C),
    (A, B, C, D),
    (A, B, C, D, E),
    (A, B, C, D, E, F),
    (A, B, C, D, E, F, G),
    (A, B, C, D, E, F, G, H),
    (A, B, C, D, E, F, G, H, I),
    (A, B, C, D, E, F, G, H, I, J),
    (A, B, C, D, E, F, G, H, I, J, K),
    (A, B, C, D, E, F, G, H, I, J, K, L), // 12
}

macro_rules! impl_deref_trace {
    ($t:ty) => {
        unsafe fn untrace(&self) {
            unsafe { (**self).untrace() };
        }

        unsafe fn trace(&self) {
            unsafe { (**self).trace() };
        }

        unsafe fn set_undone(&self) {
            unsafe { (**self).set_undone() };
        }

        fn counts_match(&self) -> bool {
            (**self).counts_match()
        }

        fn could_contain_cycles() -> bool {
            T::could_contain_cycles()
        }
    };
}

unsafe impl<T: Trace> Trace for Option<T> {
    unsafe fn untrace(&self) {
        if let Some(v) = self {
            unsafe { v.untrace() };
        }
    }

    unsafe fn trace(&self) {
        if let Some(v) = self {
            unsafe { v.trace() };
        }
    }

    unsafe fn set_undone(&self) {
        if let Some(v) = self {
            unsafe { v.set_undone() };
        }
    }

    fn counts_match(&self) -> bool {
        if let Some(v) = self {
            v.counts_match()
        } else {
            true
        }
    }

    fn could_contain_cycles() -> bool {
        T::could_contain_cycles()
    }
}

unsafe impl<T: Trace + ?Sized> Trace for &'_ T {
    impl_deref_trace! { T }
}

unsafe impl<T: Trace + ?Sized> Trace for &'_ mut T {
    impl_deref_trace! { T }
}

unsafe impl<T: Trace + ?Sized> Trace for Box<T> {
    impl_deref_trace! { T }
}

unsafe impl<T: Trace> Trace for Vec<T> {
    impl_deref_trace! { [T] }
}

unsafe impl<T: Trace> Trace for [T] {
    unsafe fn untrace(&self) {
        for v in self {
            unsafe { v.untrace() };
        }
    }

    unsafe fn trace(&self) {
        for v in self {
            unsafe { v.trace() };
        }
    }

    unsafe fn set_undone(&self) {
        for v in self {
            unsafe { v.set_undone() };
        }
    }

    fn counts_match(&self) -> bool {
        self.iter().all(Trace::counts_match)
    }

    fn could_contain_cycles() -> bool {
        T::could_contain_cycles()
    }
}

unsafe impl<T: Trace> Trace for RefCell<T> {
    unsafe fn untrace(&self) {
        if let Ok(v) = self.try_borrow() {
            unsafe { v.untrace() };
        }
    }

    unsafe fn trace(&self) {
        if let Ok(v) = self.try_borrow() {
            unsafe { v.trace() };
        }
    }

    unsafe fn set_undone(&self) {
        if let Ok(v) = self.try_borrow() {
            unsafe { v.set_undone() };
        }
    }

    fn counts_match(&self) -> bool {
        if let Ok(v) = self.try_borrow() {
            v.counts_match()
        } else {
            true
        }
    }

    fn could_contain_cycles() -> bool {
        T::could_contain_cycles()
    }
}