use std::{
marker::PhantomData,
num::NonZero,
os::raw::{c_int, c_void},
};
use crate::{ffi, Py};
#[repr(transparent)]
pub struct PyTraverseError(NonZero<c_int>);
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<'a, T, U: 'a>(&self, obj: T) -> Result<(), PyTraverseError>
where
T: Into<Option<&'a Py<U>>>,
{
let ptr = obj.into().map_or_else(std::ptr::null_mut, Py::as_ptr);
if !ptr.is_null() {
match NonZero::new(unsafe { (self.visit)(ptr, self.arg) }) {
None => Ok(()),
Some(r) => Err(PyTraverseError(r)),
}
} else {
Ok(())
}
}
}
#[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);
}
}