1use std::{
2 marker::PhantomData,
3 os::raw::{c_int, c_void},
4};
5
6use crate::{ffi, Py};
7
8#[repr(transparent)]
10pub struct PyTraverseError(NonZeroCInt);
11
12impl PyTraverseError {
13 pub(crate) fn into_inner(self) -> c_int {
15 self.0.into()
16 }
17}
18
19#[derive(Clone)]
21pub struct PyVisit<'a> {
22 pub(crate) visit: ffi::visitproc,
23 pub(crate) arg: *mut c_void,
24 pub(crate) _guard: PhantomData<&'a ()>,
26}
27
28impl PyVisit<'_> {
29 pub fn call<'a, T, U: 'a>(&self, obj: T) -> Result<(), PyTraverseError>
36 where
37 T: Into<Option<&'a Py<U>>>,
38 {
39 let ptr = obj.into().map_or_else(std::ptr::null_mut, Py::as_ptr);
40 if !ptr.is_null() {
41 match NonZeroCInt::new(unsafe { (self.visit)(ptr, self.arg) }) {
42 None => Ok(()),
43 Some(r) => Err(PyTraverseError(r)),
44 }
45 } else {
46 Ok(())
47 }
48 }
49}
50
51mod get_nonzero_c_int {
53 pub struct GetNonZeroCInt<const WIDTH: usize>();
54
55 pub trait NonZeroCIntType {
56 type Type;
57 }
58 impl NonZeroCIntType for GetNonZeroCInt<16> {
59 type Type = std::num::NonZeroI16;
60 }
61 impl NonZeroCIntType for GetNonZeroCInt<32> {
62 type Type = std::num::NonZeroI32;
63 }
64
65 pub type Type =
66 <GetNonZeroCInt<{ std::mem::size_of::<std::os::raw::c_int>() * 8 }> as NonZeroCIntType>::Type;
67}
68
69use get_nonzero_c_int::Type as NonZeroCInt;
70
71#[cfg(test)]
72mod tests {
73 use super::PyVisit;
74 use static_assertions::assert_not_impl_any;
75
76 #[test]
77 fn py_visit_not_send_sync() {
78 assert_not_impl_any!(PyVisit<'_>: Send, Sync);
79 }
80}