use std::{
marker::PhantomData,
os::raw::{c_int, c_void},
};
use crate::{ffi, AsPyPointer};
#[repr(transparent)]
pub struct PyTraverseError(NonZeroCInt);
impl PyTraverseError {
pub(crate) fn into_inner(self) -> c_int {
self.0.into()
}
}
#[derive(Clone)]
pub struct PyVisit<'a> {
pub(crate) visit: ffi::visitproc,
pub(crate) arg: *mut c_void,
pub(crate) _guard: PhantomData<&'a ()>,
}
impl PyVisit<'_> {
pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
where
T: AsPyPointer,
{
let ptr = obj.as_ptr();
if !ptr.is_null() {
match NonZeroCInt::new(unsafe { (self.visit)(ptr, self.arg) }) {
None => Ok(()),
Some(r) => Err(PyTraverseError(r)),
}
} else {
Ok(())
}
}
}
mod get_nonzero_c_int {
pub struct GetNonZeroCInt<const WIDTH: usize>();
pub trait NonZeroCIntType {
type Type;
}
impl NonZeroCIntType for GetNonZeroCInt<16> {
type Type = std::num::NonZeroI16;
}
impl NonZeroCIntType for GetNonZeroCInt<32> {
type Type = std::num::NonZeroI32;
}
pub type Type =
<GetNonZeroCInt<{ std::mem::size_of::<std::os::raw::c_int>() * 8 }> as NonZeroCIntType>::Type;
}
use get_nonzero_c_int::Type as NonZeroCInt;
#[cfg(test)]
mod tests {
use super::PyVisit;
use static_assertions::assert_not_impl_any;
#[test]
fn py_visit_not_send_sync() {
assert_not_impl_any!(PyVisit<'_>: Send, Sync);
}
}