use libc;
use ffi;
use std::mem;
use python::{Python, PythonObject, PyDrop, ToPythonPointer};
use objects::PyObject;
use function::AbortOnDrop;
pub struct TraverseError(libc::c_int);
#[derive(Copy, Clone)]
pub struct VisitProc<'a> {
visit: ffi::visitproc,
arg: *mut libc::c_void,
_py: Python<'a>
}
impl <'a> VisitProc<'a> {
pub fn call<T>(&self, obj: &T) -> Result<(), TraverseError>
where T: PythonObject
{
let r = unsafe { (self.visit)(obj.as_ptr(), self.arg) };
if r == 0 {
Ok(())
} else {
Err(TraverseError(r))
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_tp_traverse {
($class_name:ident,
/* gc: */ {
/* traverse_proc: */ None,
/* traverse_data: */ [ ]
}) => {
None
};
($class_name:ident,
/* gc: */ {
$traverse_proc: expr,
/* traverse_data: */ []
}) => {{
unsafe extern "C" fn tp_traverse(
slf: *mut $crate::_detail::ffi::PyObject,
visit: $crate::_detail::ffi::visitproc,
arg: *mut $crate::_detail::libc::c_void
) -> $crate::_detail::libc::c_int
{
$crate::py_class::gc::tp_traverse::<$class_name, _>(
concat!(stringify!($class_name), ".__traverse__"),
slf, visit, arg, $traverse_proc)
}
Some(tp_traverse)
}};
}
#[doc(hidden)]
pub unsafe fn tp_traverse<C, F>(
location: &str,
slf: *mut ffi::PyObject,
visit: ffi::visitproc,
arg: *mut libc::c_void,
callback: F
) -> libc::c_int
where C: PythonObject,
F: FnOnce(&C, Python, VisitProc) -> Result<(), TraverseError>
{
let guard = AbortOnDrop(location);
let py = Python::assume_gil_acquired();
let visit = VisitProc { visit: visit, arg: arg, _py: py };
let slf = PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<C>();
let ret = match callback(&slf, py, visit) {
Ok(()) => 0,
Err(TraverseError(code)) => code
};
slf.release_ref(py);
mem::forget(guard);
ret
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_class_tp_clear {
($class_name:ident) => {{
unsafe extern "C" fn tp_clear(
slf: *mut $crate::_detail::ffi::PyObject
) -> $crate::_detail::libc::c_int
{
$crate::py_class::gc::tp_clear::<$class_name, _>(
concat!(stringify!($class_name), ".__clear__"),
slf, $class_name::__clear__)
}
Some(tp_clear)
}}
}
#[doc(hidden)]
pub unsafe fn tp_clear<C, F>(
location: &str,
slf: *mut ffi::PyObject,
callback: F
) -> libc::c_int
where C: PythonObject,
F: FnOnce(&C, Python)
{
let guard = AbortOnDrop(location);
let py = Python::assume_gil_acquired();
let slf = PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<C>();
callback(&slf, py);
slf.release_ref(py);
mem::forget(guard);
0
}