1use core::ptr::NonNull;
2
3use rustpython_common::lock::{PyMutex, PyRwLock};
4
5use crate::{
6 AsObject, PyObject, PyObjectRef, PyRef, PyStackRef, function::Either, object::PyObjectPayload,
7};
8
9pub type TraverseFn<'a> = dyn FnMut(&PyObject) + 'a;
10
11pub trait MaybeTraverse {
16 const HAS_TRAVERSE: bool = false;
18 const HAS_CLEAR: bool = false;
20 fn try_traverse(&self, traverse_fn: &mut TraverseFn<'_>);
22 fn try_clear(&mut self, _out: &mut Vec<PyObjectRef>) {}
24}
25
26pub unsafe trait Traverse {
30 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>);
37
38 fn clear(&mut self, _out: &mut Vec<PyObjectRef>) {}
42}
43
44unsafe impl Traverse for PyObjectRef {
45 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
46 traverse_fn(self)
47 }
48}
49
50unsafe impl Traverse for PyStackRef {
51 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
52 if !self.is_borrowed() {
59 traverse_fn(self.as_object())
60 }
61 }
62}
63
64unsafe impl<T: PyObjectPayload> Traverse for PyRef<T> {
65 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
66 traverse_fn(self.as_object())
67 }
68}
69
70unsafe impl Traverse for () {
71 fn traverse(&self, _traverse_fn: &mut TraverseFn<'_>) {}
72}
73
74unsafe impl<T: Traverse> Traverse for Option<T> {
75 #[inline]
76 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
77 if let Some(v) = self {
78 v.traverse(traverse_fn);
79 }
80 }
81}
82
83unsafe impl<T> Traverse for [T]
84where
85 T: Traverse,
86{
87 #[inline]
88 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
89 for elem in self {
90 elem.traverse(traverse_fn);
91 }
92 }
93}
94
95unsafe impl<T> Traverse for Box<[T]>
96where
97 T: Traverse,
98{
99 #[inline]
100 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
101 for elem in &**self {
102 elem.traverse(traverse_fn);
103 }
104 }
105}
106
107unsafe impl<T> Traverse for Vec<T>
108where
109 T: Traverse,
110{
111 #[inline]
112 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
113 for elem in self {
114 elem.traverse(traverse_fn);
115 }
116 }
117}
118
119unsafe impl<T: crate::PyPayload> Traverse for super::ext::PyAtomicRef<Option<T>> {
120 #[inline]
121 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
122 if let Some(obj) = self.deref() {
123 traverse_fn(obj.as_object());
124 }
125 }
126}
127
128unsafe impl<T: crate::PyPayload> Traverse for super::ext::PyAtomicRef<T> {
129 #[inline]
130 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
131 traverse_fn(self.as_object());
132 }
133}
134
135unsafe impl Traverse for super::ext::PyAtomicRef<PyObject> {
136 #[inline]
137 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
138 traverse_fn(self);
139 }
140}
141
142unsafe impl Traverse for super::ext::PyAtomicRef<Option<PyObject>> {
143 #[inline]
144 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
145 let ptr = self.load_ptr();
146 if let Some(obj) = unsafe { ptr.as_ref() } {
149 traverse_fn(obj);
150 }
151 }
152}
153
154unsafe impl<T: Traverse> Traverse for PyRwLock<T> {
155 #[inline]
156 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
157 if let Some(inner) = self.try_read_recursive() {
167 inner.traverse(traverse_fn)
168 }
169 }
170}
171
172unsafe impl<T: Traverse> Traverse for PyMutex<T> {
177 #[inline]
178 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
179 let mut chs: Vec<NonNull<PyObject>> = Vec::new();
180 if let Some(obj) = self.try_lock() {
181 obj.traverse(&mut |ch| {
182 chs.push(NonNull::from(ch));
183 })
184 }
185 chs.iter()
186 .map(|ch| {
187 let ch = unsafe { ch.as_ref() };
191 traverse_fn(ch);
192 })
193 .count();
194 }
195}
196
197macro_rules! trace_tuple {
198 ($(($NAME: ident, $NUM: tt)),*) => {
199 unsafe impl<$($NAME: Traverse),*> Traverse for ($($NAME),*) {
200 #[inline]
201 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
202 $(
203 self.$NUM.traverse(traverse_fn);
204 )*
205 }
206 }
207
208 };
209}
210
211unsafe impl<A: Traverse, B: Traverse> Traverse for Either<A, B> {
212 #[inline]
213 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
214 match self {
215 Self::A(a) => a.traverse(tracer_fn),
216 Self::B(b) => b.traverse(tracer_fn),
217 }
218 }
219}
220
221unsafe impl<A: Traverse> Traverse for (A,) {
224 #[inline]
225 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
226 self.0.traverse(tracer_fn);
227 }
228}
229
230trace_tuple!((A, 0), (B, 1));
231trace_tuple!((A, 0), (B, 1), (C, 2));
232trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3));
233trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4));
234trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5));
235trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6));
236trace_tuple!(
237 (A, 0),
238 (B, 1),
239 (C, 2),
240 (D, 3),
241 (E, 4),
242 (F, 5),
243 (G, 6),
244 (H, 7)
245);
246trace_tuple!(
247 (A, 0),
248 (B, 1),
249 (C, 2),
250 (D, 3),
251 (E, 4),
252 (F, 5),
253 (G, 6),
254 (H, 7),
255 (I, 8)
256);
257trace_tuple!(
258 (A, 0),
259 (B, 1),
260 (C, 2),
261 (D, 3),
262 (E, 4),
263 (F, 5),
264 (G, 6),
265 (H, 7),
266 (I, 8),
267 (J, 9)
268);
269trace_tuple!(
270 (A, 0),
271 (B, 1),
272 (C, 2),
273 (D, 3),
274 (E, 4),
275 (F, 5),
276 (G, 6),
277 (H, 7),
278 (I, 8),
279 (J, 9),
280 (K, 10)
281);
282trace_tuple!(
283 (A, 0),
284 (B, 1),
285 (C, 2),
286 (D, 3),
287 (E, 4),
288 (F, 5),
289 (G, 6),
290 (H, 7),
291 (I, 8),
292 (J, 9),
293 (K, 10),
294 (L, 11)
295);