rustpython_vm/object/
traverse_object.rs1use alloc::fmt;
2use core::any::TypeId;
3
4use crate::{
5 PyObject, PyObjectRef,
6 object::{
7 Erased, InstanceDict, MaybeTraverse, Py, PyObjectPayload, debug_obj, default_dealloc,
8 try_clear_obj, try_traverse_obj,
9 },
10};
11
12use super::{Traverse, TraverseFn};
13
14pub(in crate::object) struct PyObjVTable {
15 pub(in crate::object) typeid: TypeId,
16 pub(in crate::object) dealloc: unsafe fn(*mut PyObject),
18 pub(in crate::object) debug: unsafe fn(&PyObject, &mut fmt::Formatter<'_>) -> fmt::Result,
19 pub(in crate::object) trace: Option<unsafe fn(&PyObject, &mut TraverseFn<'_>)>,
20 pub(in crate::object) clear: Option<unsafe fn(*mut PyObject, &mut Vec<PyObjectRef>)>,
23}
24
25impl PyObjVTable {
26 pub(super) const fn of<T: PyObjectPayload>() -> &'static Self {
27 &Self {
28 typeid: T::PAYLOAD_TYPE_ID,
29 dealloc: default_dealloc::<T>,
30 debug: debug_obj::<T>,
31 trace: const {
32 if T::HAS_TRAVERSE {
33 Some(try_traverse_obj::<T>)
34 } else {
35 None
36 }
37 },
38 clear: const {
39 if T::HAS_CLEAR {
40 Some(try_clear_obj::<T>)
41 } else {
42 None
43 }
44 },
45 }
46 }
47}
48
49unsafe impl Traverse for InstanceDict {
50 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
51 self.dict.traverse(tracer_fn)
52 }
53}
54
55unsafe impl Traverse for Py<Erased> {
56 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
58 let typ = &*self.typ;
63 if typ.heaptype_ext.is_some() {
64 let typ_obj: &PyObject = unsafe { &*(typ as *const _ as *const PyObject) };
66 tracer_fn(typ_obj);
67 }
68 if let Some(ext) = self.ext_ref() {
70 ext.dict.traverse(tracer_fn);
71 for slot in self.slot_cells() {
72 slot.traverse(tracer_fn);
73 }
74 }
75
76 if let Some(f) = self.vtable.trace {
77 unsafe {
78 let zelf = &*(self as *const Self as *const PyObject);
79 f(zelf, tracer_fn)
80 }
81 };
82 }
83}
84
85unsafe impl<T: MaybeTraverse> Traverse for Py<T> {
86 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
91 let typ = &*self.typ;
93 if typ.heaptype_ext.is_some() {
94 let typ_obj: &PyObject = unsafe { &*(typ as *const _ as *const PyObject) };
95 tracer_fn(typ_obj);
96 }
97 if let Some(ext) = self.ext_ref() {
99 ext.dict.traverse(tracer_fn);
100 for slot in self.slot_cells() {
101 slot.traverse(tracer_fn);
102 }
103 }
104 T::try_traverse(&self.payload, tracer_fn);
105 }
106}