use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
pub struct Gc<T> {
index: u32,
generation: u32,
marker: PhantomData<fn() -> T>,
}
impl<T> Gc<T> {
#[inline]
pub(crate) const fn new(index: u32, generation: u32) -> Self {
Self {
index,
generation,
marker: PhantomData,
}
}
#[inline]
pub(crate) const fn index(self) -> u32 {
self.index
}
#[inline]
pub(crate) const fn generation(self) -> u32 {
self.generation
}
}
impl<T> Clone for Gc<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Gc<T> {}
impl<T> PartialEq for Gc<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.index == other.index && self.generation == other.generation
}
}
impl<T> Eq for Gc<T> {}
impl<T> PartialOrd for Gc<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T> Ord for Gc<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.index
.cmp(&other.index)
.then(self.generation.cmp(&other.generation))
}
}
impl<T> Hash for Gc<T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
self.generation.hash(state);
}
}
impl<T> fmt::Debug for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Gc({}@{})", self.index, self.generation)
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
extern crate alloc;
use alloc::collections::BTreeSet;
use alloc::format;
use crate::{Heap, Trace, Tracer};
struct Leaf;
impl Trace for Leaf {
fn trace(&self, _: &mut Tracer<'_>) {}
}
#[test]
fn test_handle_traits_do_not_depend_on_the_tag() {
struct NotClone;
impl Trace for NotClone {
fn trace(&self, _: &mut Tracer<'_>) {}
}
let mut heap = Heap::<NotClone>::new();
let handle = heap.alloc(NotClone);
let copy = handle; assert_eq!(handle, copy); assert!(format!("{handle:?}").starts_with("Gc")); }
#[test]
fn test_distinct_allocations_have_distinct_handles() {
let mut heap = Heap::new();
let handles: BTreeSet<_> = (0..16).map(|_| heap.alloc(Leaf)).collect();
assert_eq!(handles.len(), 16); }
#[test]
fn test_handle_is_eight_bytes_for_any_element() {
assert_eq!(core::mem::size_of::<crate::Gc<u8>>(), 8);
assert_eq!(core::mem::size_of::<crate::Gc<[u128; 4]>>(), 8);
}
}