1use std::{
2 marker::PhantomData,
3 os::raw::{c_int, c_void},
4};
5
6use crate::{ffi, AsPyPointer};
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<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
46mod 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}