use std::any::TypeId;
use crate::{GcBox, GcErasedPointer, Trace, Tracer};
pub(crate) const fn vtable_of<T: Trace + 'static>() -> &'static VTable {
trait HasVTable: Trace + Sized + 'static {
const VTABLE: &'static VTable;
unsafe fn trace_fn(this: GcErasedPointer, tracer: &mut Tracer) {
let value = unsafe { this.cast::<GcBox<Self>>().as_ref().value() };
unsafe {
Trace::trace(value, tracer);
}
}
unsafe fn trace_non_roots_fn(this: GcErasedPointer) {
let value = unsafe { this.cast::<GcBox<Self>>().as_ref().value() };
unsafe {
Self::trace_non_roots(value);
}
}
unsafe fn run_finalizer_fn(this: GcErasedPointer) {
let value = unsafe { this.cast::<GcBox<Self>>().as_ref().value() };
Self::run_finalizer(value);
}
unsafe fn drop_fn(this: GcErasedPointer) {
let this = this.cast::<GcBox<Self>>();
let _value = unsafe { Box::from_raw(this.as_ptr()) };
}
fn type_id_fn() -> TypeId {
TypeId::of::<Self>()
}
}
impl<T: Trace + 'static> HasVTable for T {
const VTABLE: &'static VTable = &VTable {
trace_fn: T::trace_fn,
trace_non_roots_fn: T::trace_non_roots_fn,
run_finalizer_fn: T::run_finalizer_fn,
drop_fn: T::drop_fn,
type_id_fn: T::type_id_fn,
size: size_of::<GcBox<T>>(),
};
}
T::VTABLE
}
pub(crate) type TraceFn = unsafe fn(this: GcErasedPointer, tracer: &mut Tracer);
pub(crate) type TraceNonRootsFn = unsafe fn(this: GcErasedPointer);
pub(crate) type RunFinalizerFn = unsafe fn(this: GcErasedPointer);
pub(crate) type DropFn = unsafe fn(this: GcErasedPointer);
pub(crate) type TypeIdFn = fn() -> TypeId;
#[derive(Debug)]
pub(crate) struct VTable {
trace_fn: TraceFn,
trace_non_roots_fn: TraceNonRootsFn,
run_finalizer_fn: RunFinalizerFn,
drop_fn: DropFn,
type_id_fn: TypeIdFn,
size: usize,
}
impl VTable {
pub(crate) fn trace_fn(&self) -> TraceFn {
self.trace_fn
}
pub(crate) fn trace_non_roots_fn(&self) -> TraceNonRootsFn {
self.trace_non_roots_fn
}
pub(crate) fn run_finalizer_fn(&self) -> RunFinalizerFn {
self.run_finalizer_fn
}
pub(crate) fn drop_fn(&self) -> DropFn {
self.drop_fn
}
pub(crate) fn type_id(&self) -> TypeId {
(self.type_id_fn)()
}
pub(crate) fn size(&self) -> usize {
self.size
}
}