use alloc::fmt;
use core::any::TypeId;
use crate::{
PyObject, PyObjectRef,
object::{
Erased, InstanceDict, MaybeTraverse, PyInner, PyObjectPayload, debug_obj, default_dealloc,
try_clear_obj, try_traverse_obj,
},
};
use super::{Traverse, TraverseFn};
pub(in crate::object) struct PyObjVTable {
pub(in crate::object) typeid: TypeId,
pub(in crate::object) dealloc: unsafe fn(*mut PyObject),
pub(in crate::object) debug: unsafe fn(&PyObject, &mut fmt::Formatter<'_>) -> fmt::Result,
pub(in crate::object) trace: Option<unsafe fn(&PyObject, &mut TraverseFn<'_>)>,
pub(in crate::object) clear: Option<unsafe fn(*mut PyObject, &mut Vec<PyObjectRef>)>,
}
impl PyObjVTable {
pub const fn of<T: PyObjectPayload>() -> &'static Self {
&Self {
typeid: T::PAYLOAD_TYPE_ID,
dealloc: default_dealloc::<T>,
debug: debug_obj::<T>,
trace: const {
if T::HAS_TRAVERSE {
Some(try_traverse_obj::<T>)
} else {
None
}
},
clear: const {
if T::HAS_CLEAR {
Some(try_clear_obj::<T>)
} else {
None
}
},
}
}
}
unsafe impl Traverse for InstanceDict {
fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
self.d.traverse(tracer_fn)
}
}
unsafe impl Traverse for PyInner<Erased> {
fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
let typ = &*self.typ;
if typ.heaptype_ext.is_some() {
let typ_obj: &PyObject = unsafe { &*(typ as *const _ as *const PyObject) };
tracer_fn(typ_obj);
}
if let Some(ext) = self.ext_ref() {
ext.dict.traverse(tracer_fn);
ext.slots.traverse(tracer_fn);
}
if let Some(f) = self.vtable.trace {
unsafe {
let zelf = &*(self as *const Self as *const PyObject);
f(zelf, tracer_fn)
}
};
}
}
unsafe impl<T: MaybeTraverse> Traverse for PyInner<T> {
fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
let typ = &*self.typ;
if typ.heaptype_ext.is_some() {
let typ_obj: &PyObject = unsafe { &*(typ as *const _ as *const PyObject) };
tracer_fn(typ_obj);
}
if let Some(ext) = self.ext_ref() {
ext.dict.traverse(tracer_fn);
ext.slots.traverse(tracer_fn);
}
T::try_traverse(&self.payload, tracer_fn);
}
}