use std::ptr::NonNull;
use rustpython_common::lock::{PyMutex, PyRwLock};
use crate::{function::Either, object::PyObjectPayload, AsObject, PyObject, PyObjectRef, PyRef};
pub type TraverseFn<'a> = dyn FnMut(&PyObject) + 'a;
pub trait MaybeTraverse {
const IS_TRACE: bool = false;
fn try_traverse(&self, traverse_fn: &mut TraverseFn);
}
pub unsafe trait Traverse {
fn traverse(&self, traverse_fn: &mut TraverseFn);
}
unsafe impl Traverse for PyObjectRef {
fn traverse(&self, traverse_fn: &mut TraverseFn) {
traverse_fn(self)
}
}
unsafe impl<T: PyObjectPayload> Traverse for PyRef<T> {
fn traverse(&self, traverse_fn: &mut TraverseFn) {
traverse_fn(self.as_object())
}
}
unsafe impl Traverse for () {
fn traverse(&self, _traverse_fn: &mut TraverseFn) {}
}
unsafe impl<T: Traverse> Traverse for Option<T> {
#[inline]
fn traverse(&self, traverse_fn: &mut TraverseFn) {
if let Some(v) = self {
v.traverse(traverse_fn);
}
}
}
unsafe impl<T> Traverse for [T]
where
T: Traverse,
{
#[inline]
fn traverse(&self, traverse_fn: &mut TraverseFn) {
for elem in self {
elem.traverse(traverse_fn);
}
}
}
unsafe impl<T> Traverse for Box<[T]>
where
T: Traverse,
{
#[inline]
fn traverse(&self, traverse_fn: &mut TraverseFn) {
for elem in &**self {
elem.traverse(traverse_fn);
}
}
}
unsafe impl<T> Traverse for Vec<T>
where
T: Traverse,
{
#[inline]
fn traverse(&self, traverse_fn: &mut TraverseFn) {
for elem in self {
elem.traverse(traverse_fn);
}
}
}
unsafe impl<T: Traverse> Traverse for PyRwLock<T> {
#[inline]
fn traverse(&self, traverse_fn: &mut TraverseFn) {
if let Some(inner) = self.try_read_recursive() {
inner.traverse(traverse_fn)
}
}
}
unsafe impl<T: Traverse> Traverse for PyMutex<T> {
#[inline]
fn traverse(&self, traverse_fn: &mut TraverseFn) {
let mut chs: Vec<NonNull<PyObject>> = Vec::new();
if let Some(obj) = self.try_lock() {
obj.traverse(&mut |ch| {
chs.push(NonNull::from(ch));
})
}
chs.iter()
.map(|ch| {
let ch = unsafe { ch.as_ref() };
traverse_fn(ch);
})
.count();
}
}
macro_rules! trace_tuple {
($(($NAME: ident, $NUM: tt)),*) => {
unsafe impl<$($NAME: Traverse),*> Traverse for ($($NAME),*) {
#[inline]
fn traverse(&self, traverse_fn: &mut TraverseFn) {
$(
self.$NUM.traverse(traverse_fn);
)*
}
}
};
}
unsafe impl<A: Traverse, B: Traverse> Traverse for Either<A, B> {
#[inline]
fn traverse(&self, tracer_fn: &mut TraverseFn) {
match self {
Either::A(a) => a.traverse(tracer_fn),
Either::B(b) => b.traverse(tracer_fn),
}
}
}
unsafe impl<A: Traverse> Traverse for (A,) {
#[inline]
fn traverse(&self, tracer_fn: &mut TraverseFn) {
self.0.traverse(tracer_fn);
}
}
trace_tuple!((A, 0), (B, 1));
trace_tuple!((A, 0), (B, 1), (C, 2));
trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3));
trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4));
trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5));
trace_tuple!((A, 0), (B, 1), (C, 2), (D, 3), (E, 4), (F, 5), (G, 6));
trace_tuple!(
(A, 0),
(B, 1),
(C, 2),
(D, 3),
(E, 4),
(F, 5),
(G, 6),
(H, 7)
);
trace_tuple!(
(A, 0),
(B, 1),
(C, 2),
(D, 3),
(E, 4),
(F, 5),
(G, 6),
(H, 7),
(I, 8)
);
trace_tuple!(
(A, 0),
(B, 1),
(C, 2),
(D, 3),
(E, 4),
(F, 5),
(G, 6),
(H, 7),
(I, 8),
(J, 9)
);
trace_tuple!(
(A, 0),
(B, 1),
(C, 2),
(D, 3),
(E, 4),
(F, 5),
(G, 6),
(H, 7),
(I, 8),
(J, 9),
(K, 10)
);
trace_tuple!(
(A, 0),
(B, 1),
(C, 2),
(D, 3),
(E, 4),
(F, 5),
(G, 6),
(H, 7),
(I, 8),
(J, 9),
(K, 10),
(L, 11)
);