1 | use std::os::raw::{c_int, c_void}; |
2 | |
3 | use crate::{ffi, AsPyPointer, Python}; |
4 | |
5 | /// Error returned by a `__traverse__` visitor implementation. |
6 | #[repr (transparent)] |
7 | pub struct PyTraverseError(pub(crate) c_int); |
8 | |
9 | /// Object visitor for GC. |
10 | #[derive (Clone)] |
11 | pub struct PyVisit<'p> { |
12 | pub(crate) visit: ffi::visitproc, |
13 | pub(crate) arg: *mut c_void, |
14 | /// VisitProc contains a Python instance to ensure that |
15 | /// 1) it is cannot be moved out of the traverse() call |
16 | /// 2) it cannot be sent to other threads |
17 | pub(crate) _py: Python<'p>, |
18 | } |
19 | |
20 | impl<'p> PyVisit<'p> { |
21 | /// Visit `obj`. |
22 | pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError> |
23 | where |
24 | T: AsPyPointer, |
25 | { |
26 | let ptr = obj.as_ptr(); |
27 | if !ptr.is_null() { |
28 | let r = unsafe { (self.visit)(ptr, self.arg) }; |
29 | if r == 0 { |
30 | Ok(()) |
31 | } else { |
32 | Err(PyTraverseError(r)) |
33 | } |
34 | } else { |
35 | Ok(()) |
36 | } |
37 | } |
38 | |
39 | /// Creates the PyVisit from the arguments to tp_traverse |
40 | #[doc (hidden)] |
41 | pub unsafe fn from_raw(visit: ffi::visitproc, arg: *mut c_void, py: Python<'p>) -> Self { |
42 | Self { |
43 | visit, |
44 | arg, |
45 | _py: py, |
46 | } |
47 | } |
48 | } |
49 | |