pyo3/pyclass/
gc.rs

1use std::{
2    marker::PhantomData,
3    os::raw::{c_int, c_void},
4};
5
6use crate::{ffi, AsPyPointer};
7
8/// Error returned by a `__traverse__` visitor implementation.
9#[repr(transparent)]
10pub struct PyTraverseError(NonZeroCInt);
11
12impl PyTraverseError {
13    /// Returns the error code.
14    pub(crate) fn into_inner(self) -> c_int {
15        self.0.into()
16    }
17}
18
19/// Object visitor for GC.
20#[derive(Clone)]
21pub struct PyVisit<'a> {
22    pub(crate) visit: ffi::visitproc,
23    pub(crate) arg: *mut c_void,
24    /// Prevents the `PyVisit` from outliving the `__traverse__` call.
25    pub(crate) _guard: PhantomData<&'a ()>,
26}
27
28impl PyVisit<'_> {
29    /// Visit `obj`.
30    pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
31    where
32        T: AsPyPointer,
33    {
34        let ptr = obj.as_ptr();
35        if !ptr.is_null() {
36            match NonZeroCInt::new(unsafe { (self.visit)(ptr, self.arg) }) {
37                None => Ok(()),
38                Some(r) => Err(PyTraverseError(r)),
39            }
40        } else {
41            Ok(())
42        }
43    }
44}
45
46/// Workaround for `NonZero<c_int>` not being available until MSRV 1.79
47mod get_nonzero_c_int {
48    pub struct GetNonZeroCInt<const WIDTH: usize>();
49
50    pub trait NonZeroCIntType {
51        type Type;
52    }
53    impl NonZeroCIntType for GetNonZeroCInt<16> {
54        type Type = std::num::NonZeroI16;
55    }
56    impl NonZeroCIntType for GetNonZeroCInt<32> {
57        type Type = std::num::NonZeroI32;
58    }
59
60    pub type Type =
61        <GetNonZeroCInt<{ std::mem::size_of::<std::os::raw::c_int>() * 8 }> as NonZeroCIntType>::Type;
62}
63
64use get_nonzero_c_int::Type as NonZeroCInt;
65
66#[cfg(test)]
67mod tests {
68    use super::PyVisit;
69    use static_assertions::assert_not_impl_any;
70
71    #[test]
72    fn py_visit_not_send_sync() {
73        assert_not_impl_any!(PyVisit<'_>: Send, Sync);
74    }
75}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here