1use std::ptr::NonNull;
2
3use rustpython_common::lock::{PyMutex, PyRwLock};
4
5use crate::{function::Either, object::PyObjectPayload, AsObject, PyObject, PyObjectRef, PyRef};
6
7pub type TraverseFn<'a> = dyn FnMut(&PyObject) + 'a;
8
9pub trait MaybeTraverse {
14 const IS_TRACE: bool = false;
16 fn try_traverse(&self, traverse_fn: &mut TraverseFn);
18}
19
20pub unsafe trait Traverse {
24 fn traverse(&self, traverse_fn: &mut TraverseFn);
31}
32
33unsafe impl Traverse for PyObjectRef {
34 fn traverse(&self, traverse_fn: &mut TraverseFn) {
35 traverse_fn(self)
36 }
37}
38
39unsafe impl<T: PyObjectPayload> Traverse for PyRef<T> {
40 fn traverse(&self, traverse_fn: &mut TraverseFn) {
41 traverse_fn(self.as_object())
42 }
43}
44
45unsafe impl Traverse for () {
46 fn traverse(&self, _traverse_fn: &mut TraverseFn) {}
47}
48
49unsafe impl<T: Traverse> Traverse for Option<T> {
50 #[inline]
51 fn traverse(&self, traverse_fn: &mut TraverseFn) {
52 if let Some(v) = self {
53 v.traverse(traverse_fn);
54 }
55 }
56}
57
58unsafe impl<T> Traverse for [T]
59where
60 T: Traverse,
61{
62 #[inline]
63 fn traverse(&self, traverse_fn: &mut TraverseFn) {
64 for elem in self {
65 elem.traverse(traverse_fn);
66 }
67 }
68}
69
70unsafe impl<T> Traverse for Box<[T]>
71where
72 T: Traverse,
73{
74 #[inline]
75 fn traverse(&self, traverse_fn: &mut TraverseFn) {
76 for elem in &**self {
77 elem.traverse(traverse_fn);
78 }
79 }
80}
81
82unsafe impl<T> Traverse for Vec<T>
83where
84 T: Traverse,
85{
86 #[inline]
87 fn traverse(&self, traverse_fn: &mut TraverseFn) {
88 for elem in self {
89 elem.traverse(traverse_fn);
90 }
91 }
92}
93
94unsafe impl<T: Traverse> Traverse for PyRwLock<T> {
95 #[inline]
96 fn traverse(&self, traverse_fn: &mut TraverseFn) {
97 if let Some(inner) = self.try_read_recursive() {
101 inner.traverse(traverse_fn)
102 }
103 }
104}
105
106unsafe impl<T: Traverse> Traverse for PyMutex<T> {
111 #[inline]
112 fn traverse(&self, traverse_fn: &mut TraverseFn) {
113 let mut chs: Vec<NonNull<PyObject>> = Vec::new();
114 if let Some(obj) = self.try_lock() {
115 obj.traverse(&mut |ch| {
116 chs.push(NonNull::from(ch));
117 })
118 }
119 chs.iter()
120 .map(|ch| {
121 let ch = unsafe { ch.as_ref() };
123 traverse_fn(ch);
124 })
125 .count();
126 }
127}
128
129macro_rules! trace_tuple {
130 ($(($NAME: ident, $NUM: tt)),*) => {
131 unsafe impl<$($NAME: Traverse),*> Traverse for ($($NAME),*) {
132 #[inline]
133 fn traverse(&self, traverse_fn: &mut TraverseFn) {
134 $(
135 self.$NUM.traverse(traverse_fn);
136 )*
137 }
138 }
139
140 };
141}
142
143unsafe impl<A: Traverse, B: Traverse> Traverse for Either<A, B> {
144 #[inline]
145 fn traverse(&self, tracer_fn: &mut TraverseFn) {
146 match self {
147 Either::A(a) => a.traverse(tracer_fn),
148 Either::B(b) => b.traverse(tracer_fn),
149 }
150 }
151}
152
153unsafe impl<A: Traverse> Traverse for (A,) {
156 #[inline]
157 fn traverse(&self, tracer_fn: &mut TraverseFn) {
158 self.0.traverse(tracer_fn);
159 }
160}
161trace_tuple!((A, 0), (B, 1));
162trace_tuple!((A, 0), (B, 1), (C, 2));
163trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3));
164trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4));
165trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5));
166trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6));
167trace_tuple!(
168 (A, 0),
169 (B, 1),
170 (C, 2),
171 (D, 3),
172 (E, 4),
173 (F, 5),
174 (G, 6),
175 (H, 7)
176);
177trace_tuple!(
178 (A, 0),
179 (B, 1),
180 (C, 2),
181 (D, 3),
182 (E, 4),
183 (F, 5),
184 (G, 6),
185 (H, 7),
186 (I, 8)
187);
188trace_tuple!(
189 (A, 0),
190 (B, 1),
191 (C, 2),
192 (D, 3),
193 (E, 4),
194 (F, 5),
195 (G, 6),
196 (H, 7),
197 (I, 8),
198 (J, 9)
199);
200trace_tuple!(
201 (A, 0),
202 (B, 1),
203 (C, 2),
204 (D, 3),
205 (E, 4),
206 (F, 5),
207 (G, 6),
208 (H, 7),
209 (I, 8),
210 (J, 9),
211 (K, 10)
212);
213trace_tuple!(
214 (A, 0),
215 (B, 1),
216 (C, 2),
217 (D, 3),
218 (E, 4),
219 (F, 5),
220 (G, 6),
221 (H, 7),
222 (I, 8),
223 (J, 9),
224 (K, 10),
225 (L, 11)
226);