Avoid function definition in setters for readability

This commit is contained in:
kngwyu 2020-06-06 17:25:14 +09:00
parent d678093509
commit 05effe26f1
3 changed files with 160 additions and 118 deletions

View file

@ -183,54 +183,13 @@ impl PyObjectMethods {
where
T: for<'p> PyObjectGetAttrProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
) -> *mut ffi::PyObject
where
T: for<'p> PyObjectGetAttrProtocol<'p>,
{
crate::callback_body!(py, {
// Behave like python's __getattr__ (as opposed to __getattribute__) and check
// for existing fields and methods first
let existing = ffi::PyObject_GenericGetAttr(slf, arg);
if existing.is_null() {
// PyObject_HasAttr also tries to get an object and clears the error if it fails
ffi::PyErr_Clear();
} else {
return Ok(existing);
}
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<PyAny>(arg);
call_ref!(slf, __getattr__, arg)
})
}
self.tp_getattro = Some(wrap::<T>);
self.tp_getattro = tp_getattro::<T>();
}
pub fn set_richcompare<T>(&mut self)
where
T: for<'p> PyObjectRichcmpProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
op: c_int,
) -> *mut ffi::PyObject
where
T: for<'p> PyObjectRichcmpProtocol<'p>,
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<PyAny>(arg);
let op = extract_op(op)?;
let arg = arg.extract()?;
slf.try_borrow()?.__richcmp__(arg, op).into()
})
}
self.tp_richcompare = Some(wrap::<T>);
self.tp_richcompare = tp_richcompare::<T>();
}
pub fn set_setattr<T>(&mut self)
where
@ -258,16 +217,70 @@ impl PyObjectMethods {
}
}
fn extract_op(op: c_int) -> PyResult<CompareOp> {
match op {
ffi::Py_LT => Ok(CompareOp::Lt),
ffi::Py_LE => Ok(CompareOp::Le),
ffi::Py_EQ => Ok(CompareOp::Eq),
ffi::Py_NE => Ok(CompareOp::Ne),
ffi::Py_GT => Ok(CompareOp::Gt),
ffi::Py_GE => Ok(CompareOp::Ge),
_ => Err(PyErr::new::<exceptions::ValueError, _>(
"tp_richcompare called with invalid comparison operator",
)),
fn tp_getattro<T>() -> Option<ffi::binaryfunc>
where
T: for<'p> PyObjectGetAttrProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
) -> *mut ffi::PyObject
where
T: for<'p> PyObjectGetAttrProtocol<'p>,
{
crate::callback_body!(py, {
// Behave like python's __getattr__ (as opposed to __getattribute__) and check
// for existing fields and methods first
let existing = ffi::PyObject_GenericGetAttr(slf, arg);
if existing.is_null() {
// PyObject_HasAttr also tries to get an object and clears the error if it fails
ffi::PyErr_Clear();
} else {
return Ok(existing);
}
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<PyAny>(arg);
call_ref!(slf, __getattr__, arg)
})
}
Some(wrap::<T>)
}
fn tp_richcompare<T>() -> Option<ffi::richcmpfunc>
where
T: for<'p> PyObjectRichcmpProtocol<'p>,
{
fn extract_op(op: c_int) -> PyResult<CompareOp> {
match op {
ffi::Py_LT => Ok(CompareOp::Lt),
ffi::Py_LE => Ok(CompareOp::Le),
ffi::Py_EQ => Ok(CompareOp::Eq),
ffi::Py_NE => Ok(CompareOp::Ne),
ffi::Py_GT => Ok(CompareOp::Gt),
ffi::Py_GE => Ok(CompareOp::Ge),
_ => Err(PyErr::new::<exceptions::ValueError, _>(
"tp_richcompare called with invalid comparison operator",
)),
}
}
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
op: c_int,
) -> *mut ffi::PyObject
where
T: for<'p> PyObjectRichcmpProtocol<'p>,
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<PyAny>(arg);
let op = extract_op(op)?;
let arg = arg.extract()?;
slf.try_borrow()?.__richcmp__(arg, op).into()
})
}
Some(wrap::<T>)
}

View file

@ -45,34 +45,48 @@ impl PyBufferProcs {
where
T: for<'p> PyBufferGetBufferProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg1: *mut ffi::Py_buffer,
arg2: c_int,
) -> c_int
where
T: for<'p> PyBufferGetBufferProtocol<'p>,
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into()
})
}
self.bf_getbuffer = Some(wrap::<T>);
self.bf_getbuffer = bf_getbuffer::<T>();
}
pub fn set_releasebuffer<T>(&mut self)
where
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
where
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into()
})
}
self.bf_releasebuffer = Some(wrap::<T>);
self.bf_releasebuffer = bf_releasebuffer::<T>();
}
}
fn bf_getbuffer<T>() -> Option<ffi::getbufferproc>
where
T: for<'p> PyBufferGetBufferProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(
slf: *mut ffi::PyObject,
arg1: *mut ffi::Py_buffer,
arg2: c_int,
) -> c_int
where
T: for<'p> PyBufferGetBufferProtocol<'p>,
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into()
})
}
Some(wrap::<T>)
}
fn bf_releasebuffer<T>() -> Option<ffi::releasebufferproc>
where
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
{
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
where
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
{
crate::callback_body!(py, {
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into()
})
}
Some(wrap::<T>)
}

View file

@ -35,52 +35,14 @@ impl PyGCMethods {
where
T: for<'p> PyGCTraverseProtocol<'p>,
{
unsafe extern "C" fn tp_traverse<T>(
slf: *mut ffi::PyObject,
visit: ffi::visitproc,
arg: *mut c_void,
) -> c_int
where
T: for<'p> PyGCTraverseProtocol<'p>,
{
let pool = crate::GILPool::new();
let py = pool.python();
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let visit = PyVisit {
visit,
arg,
_py: py,
};
let borrow = slf.try_borrow();
if let Ok(borrow) = borrow {
match borrow.__traverse__(visit) {
Ok(()) => 0,
Err(PyTraverseError(code)) => code,
}
} else {
0
}
}
self.tp_traverse = Some(tp_traverse::<T>);
self.tp_traverse = tp_traverse::<T>();
}
pub fn set_clear<T>(&mut self)
where
T: for<'p> PyGCClearProtocol<'p>,
{
unsafe extern "C" fn tp_clear<T>(slf: *mut ffi::PyObject) -> c_int
where
T: for<'p> PyGCClearProtocol<'p>,
{
let pool = crate::GILPool::new();
let py = pool.python();
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
slf.borrow_mut().__clear__();
0
}
self.tp_clear = Some(tp_clear::<T>);
self.tp_clear = tp_clear::<T>();
}
}
@ -109,3 +71,56 @@ impl<'p> PyVisit<'p> {
}
}
}
fn tp_traverse<T>() -> Option<ffi::traverseproc>
where
T: for<'p> PyGCTraverseProtocol<'p>,
{
unsafe extern "C" fn tp_traverse<T>(
slf: *mut ffi::PyObject,
visit: ffi::visitproc,
arg: *mut c_void,
) -> c_int
where
T: for<'p> PyGCTraverseProtocol<'p>,
{
let pool = crate::GILPool::new();
let py = pool.python();
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let visit = PyVisit {
visit,
arg,
_py: py,
};
let borrow = slf.try_borrow();
if let Ok(borrow) = borrow {
match borrow.__traverse__(visit) {
Ok(()) => 0,
Err(PyTraverseError(code)) => code,
}
} else {
0
}
}
Some(tp_traverse::<T>)
}
fn tp_clear<T>() -> Option<ffi::inquiry>
where
T: for<'p> PyGCClearProtocol<'p>,
{
unsafe extern "C" fn tp_clear<T>(slf: *mut ffi::PyObject) -> c_int
where
T: for<'p> PyGCClearProtocol<'p>,
{
let pool = crate::GILPool::new();
let py = pool.python();
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
slf.borrow_mut().__clear__();
0
}
Some(tp_clear::<T>)
}