1use std::{
2 marker::PhantomData,
3 num::NonZero,
4 os::raw::{c_int, c_void},
5};
6
7use crate::{ffi, Py};
8
9#[repr(transparent)]
11pub struct PyTraverseError(NonZero<c_int>);
12
13impl PyTraverseError {
14 pub(crate) fn into_inner(self) -> c_int {
16 self.0.into()
17 }
18}
19
20#[derive(Clone)]
22pub struct PyVisit<'a> {
23 pub(crate) visit: ffi::visitproc,
24 pub(crate) arg: *mut c_void,
25 pub(crate) _guard: PhantomData<&'a ()>,
27}
28
29impl PyVisit<'_> {
30 pub fn call<'a, T, U: 'a>(&self, obj: T) -> Result<(), PyTraverseError>
37 where
38 T: Into<Option<&'a Py<U>>>,
39 {
40 let ptr = obj.into().map_or_else(std::ptr::null_mut, Py::as_ptr);
41 if !ptr.is_null() {
42 match NonZero::new(unsafe { (self.visit)(ptr, self.arg) }) {
43 None => Ok(()),
44 Some(r) => Err(PyTraverseError(r)),
45 }
46 } else {
47 Ok(())
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::PyVisit;
55 use static_assertions::assert_not_impl_any;
56
57 #[test]
58 fn py_visit_not_send_sync() {
59 assert_not_impl_any!(PyVisit<'_>: Send, Sync);
60 }
61}