Renew PyProtoMethods for new ABI3-based type construction
This commit is contained in:
parent
f74b64993e
commit
eb8ff1581b
|
@ -133,94 +133,109 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
/// All FFI functions for basic protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyObjectMethods {
|
||||
pub tp_str: Option<ffi::reprfunc>,
|
||||
pub tp_repr: Option<ffi::reprfunc>,
|
||||
pub tp_hash: Option<ffi::hashfunc>,
|
||||
pub tp_getattro: Option<ffi::getattrofunc>,
|
||||
pub tp_richcompare: Option<ffi::richcmpfunc>,
|
||||
pub tp_setattro: Option<ffi::setattrofunc>,
|
||||
pub nb_bool: Option<ffi::inquiry>,
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PyObjectMethods {
|
||||
// Set functions used by `#[pyproto]`.
|
||||
pub fn set_str<T>(&mut self)
|
||||
pub trait PyBasicSlots {
|
||||
fn get_str() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyObjectStrProtocol<'p>,
|
||||
Self: for<'p> PyObjectStrProtocol<'p>,
|
||||
{
|
||||
self.tp_str = py_unary_func!(PyObjectStrProtocol, T::__str__);
|
||||
}
|
||||
pub fn set_repr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
self.tp_repr = py_unary_func!(PyObjectReprProtocol, T::__repr__);
|
||||
}
|
||||
pub fn set_hash<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
self.tp_hash = py_unary_func!(PyObjectHashProtocol, T::__hash__, ffi::Py_hash_t);
|
||||
}
|
||||
pub fn set_getattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_getattro = tp_getattro::<T>();
|
||||
}
|
||||
pub fn set_richcompare<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
self.tp_richcompare = tp_richcompare::<T>();
|
||||
}
|
||||
pub fn set_setattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set!(PyObjectSetAttrProtocol, T, __setattr__);
|
||||
}
|
||||
pub fn set_delattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_del!(PyObjectDelAttrProtocol, T, __delattr__);
|
||||
}
|
||||
pub fn set_setdelattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
T,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
)
|
||||
}
|
||||
pub fn set_bool<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
self.nb_bool = py_unary_func!(PyObjectBoolProtocol, T::__bool__, c_int);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_str,
|
||||
pfunc: py_unary_func!(PyObjectStrProtocol, Self::__str__) as _,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) {
|
||||
slots.maybe_push(ffi::Py_tp_str, self.tp_str.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_repr, self.tp_repr.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_hash, self.tp_hash.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_getattro, self.tp_getattro.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_richcompare, self.tp_richcompare.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_setattro, self.tp_setattro.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_nb_bool, self.nb_bool.map(|v| v as _));
|
||||
fn get_repr() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_repr,
|
||||
pfunc: py_unary_func!(PyObjectReprProtocol, Self::__repr__) as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hash() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_hash,
|
||||
pfunc: py_unary_func!(PyObjectHashProtocol, Self::__hash__, ffi::Py_hash_t) as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_getattr() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_getattro,
|
||||
pfunc: tp_getattro::<Self>() as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_richcompare() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_getattro,
|
||||
pfunc: tp_richcompare::<Self>() as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_setattr() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_setattro,
|
||||
pfunc: py_func_set!(PyObjectSetAttrProtocol, Self::__setattr__) as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_delattr() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_setattro,
|
||||
pfunc: py_func_del!(PyObjectDelAttrProtocol, Self::__delattr__) as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_setdelattr() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_setattro,
|
||||
pfunc: py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
Self,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
) as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bool() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_nb_bool,
|
||||
pfunc: py_unary_func!(PyObjectBoolProtocol, Self::__bool__, c_int) as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tp_getattro<T>() -> Option<ffi::binaryfunc>
|
||||
impl<'p, T> PyBasicSlots for T where T: PyObjectProtocol<'p> {}
|
||||
|
||||
fn tp_getattro<T>() -> ffi::binaryfunc
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
|
@ -247,10 +262,10 @@ where
|
|||
call_ref!(slf, __getattr__, arg).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
wrap::<T>
|
||||
}
|
||||
|
||||
fn tp_richcompare<T>() -> Option<ffi::richcmpfunc>
|
||||
fn tp_richcompare<T>() -> ffi::richcmpfunc
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
|
@ -283,5 +298,5 @@ where
|
|||
slf.try_borrow()?.__richcmp__(arg, op).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
wrap::<T>
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::types::PyAny;
|
||||
use crate::{ffi, FromPyObject, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Descriptor interface
|
||||
#[allow(unused_variables)]
|
||||
|
@ -70,29 +69,28 @@ pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
/// All FFI functions for description protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyDescrMethods {
|
||||
pub tp_descr_get: Option<ffi::descrgetfunc>,
|
||||
pub tp_descr_set: Option<ffi::descrsetfunc>,
|
||||
/// Extension trait for our proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
pub trait PyDescrSlots {
|
||||
fn get_descr_get() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_descr_get,
|
||||
pfunc: py_ternarys_func!(PyDescrGetProtocol, Self::__get__) as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_descr_set() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_descr_set,
|
||||
pfunc: py_ternarys_func!(PyDescrSetProtocol, Self::__set__) as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl PyDescrMethods {
|
||||
pub fn set_descr_get<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_get = py_ternarys_func!(PyDescrGetProtocol, T::__get__);
|
||||
}
|
||||
pub fn set_descr_set<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_set = py_ternarys_func!(PyDescrSetProtocol, T::__set__, c_int);
|
||||
}
|
||||
pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) {
|
||||
slots.maybe_push(ffi::Py_tp_descr_get, self.tp_descr_get.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_descr_set, self.tp_descr_set.map(|v| v as _));
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyDescrSlots for T where T: PyDescrProtocol<'p> {}
|
||||
|
|
|
@ -18,35 +18,31 @@ pub trait PyGCProtocol<'p>: PyClass {
|
|||
pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
|
||||
pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
|
||||
|
||||
/// All FFI functions for gc protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyGCMethods {
|
||||
pub tp_traverse: Option<ffi::traverseproc>,
|
||||
pub tp_clear: Option<ffi::inquiry>,
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PyGCMethods {
|
||||
pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) {
|
||||
slots.maybe_push(ffi::Py_tp_traverse, self.tp_traverse.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_clear, self.tp_clear.map(|v| v as _));
|
||||
}
|
||||
|
||||
pub fn set_traverse<T>(&mut self)
|
||||
pub trait PyGCSlots {
|
||||
fn get_traverse() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
Self: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
self.tp_traverse = tp_traverse::<T>();
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_traverse,
|
||||
pfunc: tp_traverse::<Self>() as _,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_clear<T>(&mut self)
|
||||
fn get_clear() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
Self: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
self.tp_clear = tp_clear::<T>();
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_clear,
|
||||
pfunc: tp_clear::<Self>() as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyGCSlots for T where T: PyGCProtocol<'p> {}
|
||||
|
||||
/// Object visitor for GC.
|
||||
#[derive(Clone)]
|
||||
pub struct PyVisit<'p> {
|
||||
|
@ -73,7 +69,7 @@ impl<'p> PyVisit<'p> {
|
|||
}
|
||||
}
|
||||
|
||||
fn tp_traverse<T>() -> Option<ffi::traverseproc>
|
||||
fn tp_traverse<T>() -> ffi::traverseproc
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
|
@ -105,10 +101,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
Some(tp_traverse::<T>)
|
||||
tp_traverse::<T>
|
||||
}
|
||||
|
||||
fn tp_clear<T>() -> Option<ffi::inquiry>
|
||||
fn tp_clear<T>() -> ffi::inquiry
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
|
@ -123,5 +119,5 @@ where
|
|||
slf.borrow_mut().__clear__();
|
||||
0
|
||||
}
|
||||
Some(tp_clear::<T>)
|
||||
tp_clear::<T>
|
||||
}
|
||||
|
|
|
@ -71,31 +71,30 @@ pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyIterNextOutput>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyIterMethods {
|
||||
pub tp_iter: Option<ffi::getiterfunc>,
|
||||
pub tp_iternext: Option<ffi::iternextfunc>,
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
pub trait PyIterSlots {
|
||||
fn get_iter() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_iter,
|
||||
pfunc: py_unarys_func!(PyIterIterProtocol, Self::__iter__) as _,
|
||||
}
|
||||
}
|
||||
fn get_iternext() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_tp_iternext,
|
||||
pfunc: py_unarys_func!(PyIterNextProtocol, Self::__next__) as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl PyIterMethods {
|
||||
pub fn set_iter<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
self.tp_iter = py_unarys_func!(PyIterIterProtocol, T::__iter__);
|
||||
}
|
||||
pub fn set_iternext<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
self.tp_iternext = py_unarys_func!(PyIterNextProtocol, T::__next__);
|
||||
}
|
||||
pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) {
|
||||
slots.maybe_push(ffi::Py_tp_iter, self.tp_iter.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_iternext, self.tp_iternext.map(|v| v as _));
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyIterSlots for T where T: PyIterProtocol<'p> {}
|
||||
|
||||
/// Output of `__next__` which can either `yield` the next value in the iteration, or
|
||||
/// `return` a value to raise `StopIteration` in Python.
|
||||
|
|
|
@ -11,7 +11,7 @@ macro_rules! py_unary_func {
|
|||
$call!(slf, $f).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
// Use call_ref! by default
|
||||
($trait:ident, $class:ident :: $f:ident, $ret_type:ty) => {
|
||||
|
@ -34,10 +34,10 @@ macro_rules! py_unarys_func {
|
|||
<T::Receiver as $crate::derive_utils::TryFromPyCell<_>>::try_from_pycell(slf)
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
$class::$f(borrow).convert(py)
|
||||
T::$f(borrow).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ macro_rules! py_binary_func {
|
|||
$call!(slf, $f, arg).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
($trait:ident, $class:ident :: $f:ident, $return:ty) => {
|
||||
py_binary_func!($trait, $class::$f, $return, call_ref)
|
||||
|
@ -82,10 +82,10 @@ macro_rules! py_binary_num_func {
|
|||
$crate::callback_body!(py, {
|
||||
let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
|
||||
let rhs = extract_or_return_not_implemented!(py, rhs);
|
||||
$class::$f(lhs.extract()?, rhs).convert(py)
|
||||
T::$f(lhs.extract()?, rhs).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -102,10 +102,10 @@ macro_rules! py_binary_reversed_num_func {
|
|||
// Swap lhs <-> rhs
|
||||
let slf: &$crate::PyCell<T> = extract_or_return_not_implemented!(py, rhs);
|
||||
let arg = extract_or_return_not_implemented!(py, lhs);
|
||||
$class::$f(&*slf.try_borrow()?, arg).convert(py)
|
||||
T::$f(&*slf.try_borrow()?, arg).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -123,17 +123,17 @@ macro_rules! py_binary_fallback_num_func {
|
|||
let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs);
|
||||
// First, try the left hand method (e.g., __add__)
|
||||
match (lhs.extract(), rhs.extract()) {
|
||||
(Ok(l), Ok(r)) => $class::$lop(l, r).convert(py),
|
||||
(Ok(l), Ok(r)) => T::$lop(l, r).convert(py),
|
||||
_ => {
|
||||
// Next, try the right hand method (e.g., __radd__)
|
||||
let slf: &$crate::PyCell<T> = extract_or_return_not_implemented!(rhs);
|
||||
let arg = extract_or_return_not_implemented!(lhs);
|
||||
$class::$rop(&*slf.try_borrow()?, arg).convert(py)
|
||||
T::$rop(&*slf.try_borrow()?, arg).convert(py)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ macro_rules! py_binary_self_func {
|
|||
Ok::<_, $crate::err::PyErr>(slf)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ macro_rules! py_ssizearg_func {
|
|||
$call!(slf, $f; arg.into()).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -203,11 +203,11 @@ macro_rules! py_ternarys_func {
|
|||
.from_borrowed_ptr::<$crate::types::PyAny>(arg2)
|
||||
.extract()?;
|
||||
|
||||
$class::$f(slf, arg1, arg2).convert(py)
|
||||
T::$f(slf, arg1, arg2).convert(py)
|
||||
})
|
||||
}
|
||||
|
||||
Some(wrap::<T>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
($trait:ident, $class:ident :: $f:ident) => {
|
||||
py_ternarys_func!($trait, $class::$f, *mut $crate::ffi::PyObject);
|
||||
|
@ -215,8 +215,8 @@ macro_rules! py_ternarys_func {
|
|||
}
|
||||
|
||||
macro_rules! py_func_set {
|
||||
($trait_name:ident, $generic:ident, $fn_set:ident) => {{
|
||||
unsafe extern "C" fn wrap<$generic>(
|
||||
($trait_name:ident, $class:ident :: $fn_set:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
|
@ -225,12 +225,12 @@ macro_rules! py_func_set {
|
|||
T: for<'p> $trait_name<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
Err($crate::exceptions::PyNotImplementedError::new_err(format!(
|
||||
"Subscript deletion not supported by {:?}",
|
||||
stringify!($generic)
|
||||
stringify!($class)
|
||||
)))
|
||||
} else {
|
||||
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
|
||||
|
@ -240,23 +240,23 @@ macro_rules! py_func_set {
|
|||
})
|
||||
}
|
||||
|
||||
Some(wrap::<$generic>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! py_func_del {
|
||||
($trait_name:ident, $generic:ident, $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<U>(
|
||||
($trait_name:ident, $class:ident :: $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
) -> libc::c_int
|
||||
where
|
||||
U: for<'p> $trait_name<'p>,
|
||||
T: for<'p> $trait_name<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
if value.is_null() {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<U>>(slf);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let name = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(name)
|
||||
.extract()?;
|
||||
|
@ -269,13 +269,13 @@ macro_rules! py_func_del {
|
|||
})
|
||||
}
|
||||
|
||||
Some(wrap::<$generic>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! py_func_set_del {
|
||||
($trait1:ident, $trait2:ident, $generic:ident, $fn_set:ident, $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<$generic>(
|
||||
($trait1:ident, $trait2:ident, $class:ident, $fn_set:ident, $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
|
@ -284,7 +284,7 @@ macro_rules! py_func_set_del {
|
|||
T: for<'p> $trait1<'p> + for<'p> $trait2<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
|
||||
|
||||
if value.is_null() {
|
||||
|
@ -295,7 +295,7 @@ macro_rules! py_func_set_del {
|
|||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<$generic>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,17 +6,6 @@
|
|||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::{exceptions, ffi, FromPyObject, PyClass, PyObject};
|
||||
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PyMappingMethods {
|
||||
pub mp_length: Option<ffi::lenfunc>,
|
||||
pub mp_subscript: Option<ffi::binaryfunc>,
|
||||
pub mp_ass_subscript: Option<ffi::objobjargproc>,
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub use ffi::PyMappingMethods;
|
||||
|
||||
/// Mapping interface
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyMappingProtocol<'p>: PyClass {
|
||||
|
@ -83,50 +72,64 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PyMappingMethods {
|
||||
pub fn set_length<T>(&mut self)
|
||||
pub trait PyMappingSlots {
|
||||
fn get_length() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyMappingLenProtocol<'p>,
|
||||
Self: for<'p> PyMappingLenProtocol<'p>,
|
||||
{
|
||||
self.mp_length = py_len_func!(PyMappingLenProtocol, T::__len__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_mp_length,
|
||||
pfunc: py_len_func!(PyMappingLenProtocol, Self::__len__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_getitem<T>(&mut self)
|
||||
|
||||
fn get_getitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyMappingGetItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingGetItemProtocol<'p>,
|
||||
{
|
||||
self.mp_subscript = py_binary_func!(PyMappingGetItemProtocol, T::__getitem__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_mp_subscript,
|
||||
pfunc: py_binary_func!(PyMappingGetItemProtocol, Self::__getitem__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_setitem<T>(&mut self)
|
||||
|
||||
fn get_setitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingSetItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_set!(PyMappingSetItemProtocol, T, __setitem__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_mp_ass_subscript,
|
||||
pfunc: py_func_set!(PyMappingSetItemProtocol, Self::__setitem__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_delitem<T>(&mut self)
|
||||
|
||||
fn get_delitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyMappingDelItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_del!(PyMappingDelItemProtocol, T, __delitem__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_mp_ass_subscript,
|
||||
pfunc: py_func_del!(PyMappingDelItemProtocol, Self::__delitem__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_setdelitem<T>(&mut self)
|
||||
|
||||
fn get_setdelitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_set_del!(
|
||||
PyMappingSetItemProtocol,
|
||||
PyMappingDelItemProtocol,
|
||||
T,
|
||||
__setitem__,
|
||||
__delitem__
|
||||
);
|
||||
}
|
||||
pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) {
|
||||
slots.maybe_push(ffi::Py_mp_length, self.mp_length.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_mp_subscript, self.mp_subscript.map(|v| v as _));
|
||||
slots.maybe_push(
|
||||
ffi::Py_mp_ass_subscript,
|
||||
self.mp_ass_subscript.map(|v| v as _),
|
||||
);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_mp_ass_subscript,
|
||||
pfunc: py_func_set_del!(
|
||||
PyMappingSetItemProtocol,
|
||||
PyMappingDelItemProtocol,
|
||||
Self,
|
||||
__setitem__,
|
||||
__delitem__
|
||||
) as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyMappingSlots for T where T: PyMappingProtocol<'p> {}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,160 +1,55 @@
|
|||
#[cfg(not(Py_LIMITED_API))]
|
||||
use crate::class::buffer::PyBufferProcs;
|
||||
use crate::class::{
|
||||
basic::PyObjectMethods, descr::PyDescrMethods, gc::PyGCMethods, iter::PyIterMethods,
|
||||
mapping::PyMappingMethods, number::PyNumberMethods, pyasync::PyAsyncMethods,
|
||||
sequence::PySequenceMethods,
|
||||
};
|
||||
use std::{
|
||||
ptr::{self, NonNull},
|
||||
sync::atomic::{AtomicPtr, Ordering},
|
||||
};
|
||||
use crate::ffi;
|
||||
|
||||
/// Defines all method tables we need for object protocols.
|
||||
// Note(kngwyu): default implementations are for rust-numpy. Please don't remove them.
|
||||
pub trait PyProtoMethods {
|
||||
fn async_methods() -> Option<NonNull<PyAsyncMethods>> {
|
||||
None
|
||||
fn get_type_slots() -> Vec<ffi::PyType_Slot> {
|
||||
vec![]
|
||||
}
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
|
||||
None
|
||||
}
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
|
||||
None
|
||||
}
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
|
||||
None
|
||||
}
|
||||
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
|
||||
None
|
||||
}
|
||||
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
|
||||
None
|
||||
}
|
||||
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
|
||||
None
|
||||
}
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
|
||||
None
|
||||
}
|
||||
fn sequence_methods() -> Option<NonNull<PySequenceMethods>> {
|
||||
fn get_buffer() -> Option<PyBufferProcs> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that a type has a protocol registry. Implemented by `#[pyclass]`.
|
||||
#[doc(hidden)]
|
||||
pub trait HasProtoRegistry: Sized + 'static {
|
||||
fn registry() -> &'static PyProtoRegistry;
|
||||
pub enum PyProtoMethodDef {
|
||||
Slots(Vec<ffi::PyType_Slot>),
|
||||
Buffer(PyBufferProcs),
|
||||
}
|
||||
|
||||
impl<T: HasProtoRegistry> PyProtoMethods for T {
|
||||
fn async_methods() -> Option<NonNull<PyAsyncMethods>> {
|
||||
NonNull::new(Self::registry().async_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
|
||||
NonNull::new(Self::registry().basic_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
|
||||
NonNull::new(Self::registry().buffer_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
|
||||
NonNull::new(Self::registry().descr_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
|
||||
NonNull::new(Self::registry().gc_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
|
||||
NonNull::new(Self::registry().mapping_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
|
||||
NonNull::new(Self::registry().number_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
|
||||
NonNull::new(Self::registry().iter_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn sequence_methods() -> Option<NonNull<PySequenceMethods>> {
|
||||
NonNull::new(Self::registry().sequence_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores all method protocols.
|
||||
/// Used in the proc-macro code as a static variable.
|
||||
#[doc(hidden)]
|
||||
pub struct PyProtoRegistry {
|
||||
/// Async protocols.
|
||||
async_methods: AtomicPtr<PyAsyncMethods>,
|
||||
/// Basic protocols.
|
||||
basic_methods: AtomicPtr<PyObjectMethods>,
|
||||
/// Buffer protocols.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
buffer_methods: AtomicPtr<PyBufferProcs>,
|
||||
/// Descr pProtocols.
|
||||
descr_methods: AtomicPtr<PyDescrMethods>,
|
||||
/// GC protocols.
|
||||
gc_methods: AtomicPtr<PyGCMethods>,
|
||||
/// Mapping protocols.
|
||||
mapping_methods: AtomicPtr<PyMappingMethods>,
|
||||
/// Number protocols.
|
||||
number_methods: AtomicPtr<PyNumberMethods>,
|
||||
/// Iterator protocols.
|
||||
iter_methods: AtomicPtr<PyIterMethods>,
|
||||
/// Sequence protocols.
|
||||
sequence_methods: AtomicPtr<PySequenceMethods>,
|
||||
#[cfg(feature = "macros")]
|
||||
pub trait PyProtoMethodsInventory: inventory::Collect {
|
||||
fn new(methods: PyProtoMethodDef) -> Self;
|
||||
fn get(&'static self) -> &'static PyProtoMethodDef;
|
||||
}
|
||||
|
||||
impl PyProtoRegistry {
|
||||
pub const fn new() -> Self {
|
||||
PyProtoRegistry {
|
||||
async_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
basic_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
buffer_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
descr_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
gc_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
mapping_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
number_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
iter_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
sequence_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "macros")]
|
||||
pub trait HasProtoMethodsInventory {
|
||||
type ProtoMethods: PyProtoMethodsInventory;
|
||||
}
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
impl<T: HasProtoMethodsInventory> PyProtoMethods for T {
|
||||
fn get_type_slots() -> Vec<ffi::PyType_Slot> {
|
||||
inventory::iter::<T::ProtoMethods>
|
||||
.into_iter()
|
||||
.filter_map(|def| match def.get() {
|
||||
PyProtoMethodDef::Slots(slots) => Some(slots),
|
||||
PyProtoMethodDef::Buffer(_) => None,
|
||||
})
|
||||
.flatten()
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
pub fn set_async_methods(&self, methods: PyAsyncMethods) {
|
||||
self.async_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_basic_methods(&self, methods: PyObjectMethods) {
|
||||
self.basic_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn set_buffer_methods(&self, methods: PyBufferProcs) {
|
||||
self.buffer_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_descr_methods(&self, methods: PyDescrMethods) {
|
||||
self.descr_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_gc_methods(&self, methods: PyGCMethods) {
|
||||
self.gc_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_mapping_methods(&self, methods: PyMappingMethods) {
|
||||
self.mapping_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_number_methods(&self, methods: PyNumberMethods) {
|
||||
self.number_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_iter_methods(&self, methods: PyIterMethods) {
|
||||
self.iter_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_sequence_methods(&self, methods: PySequenceMethods) {
|
||||
self.sequence_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
|
||||
fn get_buffer() -> Option<PyBufferProcs> {
|
||||
inventory::iter::<T::ProtoMethods>
|
||||
.into_iter()
|
||||
.find_map(|def| match def.get() {
|
||||
PyProtoMethodDef::Slots(_) => None,
|
||||
PyProtoMethodDef::Buffer(buf) => Some(buf.clone()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,34 +96,43 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PyAsyncMethods {
|
||||
pub fn set_await<T>(&mut self)
|
||||
pub trait PyAsyncSlots {
|
||||
fn get_await() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PyAsyncAwaitProtocol<'p>,
|
||||
Self: for<'p> PyAsyncAwaitProtocol<'p>,
|
||||
{
|
||||
self.am_await = py_unarys_func!(PyAsyncAwaitProtocol, T::__await__);
|
||||
}
|
||||
pub fn set_aiter<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyAsyncAiterProtocol<'p>,
|
||||
{
|
||||
self.am_aiter = py_unarys_func!(PyAsyncAiterProtocol, T::__aiter__);
|
||||
}
|
||||
pub fn set_anext<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
self.am_anext = am_anext::<T>();
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_am_await,
|
||||
pfunc: py_unarys_func!(PyAsyncAwaitProtocol, Self::__await__) as _,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) {
|
||||
slots.maybe_push(ffi::Py_am_await, self.am_await.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_am_aiter, self.am_aiter.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_am_anext, self.am_anext.map(|v| v as _));
|
||||
fn get_aiter() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyAsyncAiterProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_am_await,
|
||||
pfunc: py_unarys_func!(PyAsyncAiterProtocol, Self::__aiter__) as _,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_anext() -> ffi::PyType_Slot
|
||||
where
|
||||
Self: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_am_anext,
|
||||
pfunc: py_unarys_func!(PyAsyncAnextProtocol, Self::__anext__) as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyAsyncSlots for T where T: PyAsyncProtocol<'p> {}
|
||||
|
||||
/// Output of `__anext__`.
|
||||
pub enum IterANextOutput<T, U> {
|
||||
Yield(T),
|
||||
Return(U),
|
||||
|
@ -166,11 +175,3 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn am_anext<T>() -> Option<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
py_unarys_func!(PyAsyncAnextProtocol, T::__anext__)
|
||||
}
|
||||
|
|
|
@ -167,103 +167,119 @@ pub trait PySequenceInplaceRepeatProtocol<'p>:
|
|||
type Result: IntoPyCallbackOutput<Self>;
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PySequenceMethods {
|
||||
pub fn set_len<T>(&mut self)
|
||||
pub trait PySequenceSlots {
|
||||
fn get_len() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceLenProtocol<'p>,
|
||||
Self: for<'p> PySequenceLenProtocol<'p>,
|
||||
{
|
||||
self.sq_length = py_len_func!(PySequenceLenProtocol, T::__len__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: py_len_func!(PySequenceLenProtocol, Self::__len__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_concat<T>(&mut self)
|
||||
fn get_concat() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceConcatProtocol<'p>,
|
||||
Self: for<'p> PySequenceConcatProtocol<'p>,
|
||||
{
|
||||
self.sq_concat = py_binary_func!(PySequenceConcatProtocol, T::__concat__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: py_binary_func!(PySequenceConcatProtocol, Self::__concat__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_repeat<T>(&mut self)
|
||||
fn get_repeat() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceRepeatProtocol<'p>,
|
||||
Self: for<'p> PySequenceRepeatProtocol<'p>,
|
||||
{
|
||||
self.sq_repeat = py_ssizearg_func!(PySequenceRepeatProtocol, T::__repeat__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: py_ssizearg_func!(PySequenceRepeatProtocol, Self::__repeat__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_getitem<T>(&mut self)
|
||||
fn get_getitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceGetItemProtocol<'p>,
|
||||
Self: for<'p> PySequenceGetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_item = py_ssizearg_func!(PySequenceGetItemProtocol, T::__getitem__);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: py_ssizearg_func!(PySequenceGetItemProtocol, Self::__getitem__) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_setitem<T>(&mut self)
|
||||
fn get_setitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
Self: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::set_item::<T>();
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: sq_ass_item_impl::set_item::<Self>() as _,
|
||||
}
|
||||
}
|
||||
pub fn set_delitem<T>(&mut self)
|
||||
fn get_delitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
Self: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::del_item::<T>();
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: sq_ass_item_impl::del_item::<Self>() as _,
|
||||
}
|
||||
}
|
||||
pub fn set_setdelitem<T>(&mut self)
|
||||
fn get_setdelitem() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>,
|
||||
Self: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::set_del_item::<T>();
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: sq_ass_item_impl::set_del_item::<Self>() as _,
|
||||
}
|
||||
}
|
||||
pub fn set_contains<T>(&mut self)
|
||||
fn get_contains() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceContainsProtocol<'p>,
|
||||
Self: for<'p> PySequenceContainsProtocol<'p>,
|
||||
{
|
||||
self.sq_contains = py_binary_func!(PySequenceContainsProtocol, T::__contains__, c_int);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: py_binary_func!(PySequenceContainsProtocol, Self::__contains__, c_int) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_inplace_concat<T>(&mut self)
|
||||
fn get_inplace_concat() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceInplaceConcatProtocol<'p>,
|
||||
Self: for<'p> PySequenceInplaceConcatProtocol<'p>,
|
||||
{
|
||||
self.sq_inplace_concat = py_binary_func!(
|
||||
PySequenceInplaceConcatProtocol,
|
||||
T::__inplace_concat__,
|
||||
*mut ffi::PyObject,
|
||||
call_mut
|
||||
)
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: py_binary_func!(
|
||||
PySequenceInplaceConcatProtocol,
|
||||
Self::__inplace_concat__,
|
||||
*mut ffi::PyObject,
|
||||
call_mut
|
||||
) as _,
|
||||
}
|
||||
}
|
||||
pub fn set_inplace_repeat<T>(&mut self)
|
||||
fn get_inplace_repeat() -> ffi::PyType_Slot
|
||||
where
|
||||
T: for<'p> PySequenceInplaceRepeatProtocol<'p>,
|
||||
Self: for<'p> PySequenceInplaceRepeatProtocol<'p>,
|
||||
{
|
||||
self.sq_inplace_repeat = py_ssizearg_func!(
|
||||
PySequenceInplaceRepeatProtocol,
|
||||
T::__inplace_repeat__,
|
||||
call_mut
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) {
|
||||
slots.maybe_push(ffi::Py_sq_length, self.sq_length.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_sq_concat, self.sq_concat.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_sq_repeat, self.sq_repeat.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_sq_item, self.sq_item.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_sq_ass_item, self.sq_ass_item.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_sq_contains, self.sq_contains.map(|v| v as _));
|
||||
slots.maybe_push(
|
||||
ffi::Py_sq_inplace_concat,
|
||||
self.sq_inplace_concat.map(|v| v as _),
|
||||
);
|
||||
slots.maybe_push(
|
||||
ffi::Py_sq_inplace_repeat,
|
||||
self.sq_inplace_repeat.map(|v| v as _),
|
||||
);
|
||||
ffi::PyType_Slot {
|
||||
slot: ffi::Py_sq_length,
|
||||
pfunc: py_ssizearg_func!(
|
||||
PySequenceInplaceRepeatProtocol,
|
||||
Self::__inplace_repeat__,
|
||||
call_mut
|
||||
) as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceSlots for T where T: PySequenceProtocol<'p> {}
|
||||
|
||||
/// It can be possible to delete and set items (PySequenceSetItemProtocol and
|
||||
/// PySequenceDelItemProtocol implemented), only to delete (PySequenceDelItemProtocol implemented)
|
||||
/// or no deleting or setting is possible
|
||||
mod sq_ass_item_impl {
|
||||
use super::*;
|
||||
|
||||
pub(super) fn set_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
pub(super) fn set_item<T>() -> ffi::ssizeobjargproc
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
|
@ -291,10 +307,10 @@ mod sq_ass_item_impl {
|
|||
crate::callback::convert(py, slf.__setitem__(key.into(), value))
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
wrap::<T>
|
||||
}
|
||||
|
||||
pub(super) fn del_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
pub(super) fn del_item<T>() -> ffi::ssizeobjargproc
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
|
@ -319,10 +335,10 @@ mod sq_ass_item_impl {
|
|||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
wrap::<T>
|
||||
}
|
||||
|
||||
pub(super) fn set_del_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
pub(super) fn set_del_item<T>() -> ffi::ssizeobjargproc
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
|
@ -347,6 +363,6 @@ mod sq_ass_item_impl {
|
|||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
wrap::<T>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,8 +147,8 @@ impl TypeSlots {
|
|||
self.0.push(ffi::PyType_Slot { slot, pfunc });
|
||||
}
|
||||
pub(crate) fn maybe_push(&mut self, slot: c_int, value: Option<*mut c_void>) {
|
||||
if let Some(v) = value {
|
||||
self.push(slot, v);
|
||||
if let Some(pfunc) = value {
|
||||
self.push(slot, pfunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +189,7 @@ where
|
|||
let (new, call, methods) = py_class_method_defs::<T>();
|
||||
slots.maybe_push(ffi::Py_tp_new, new.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_call, call.map(|v| v as _));
|
||||
|
||||
// normal methods
|
||||
if !methods.is_empty() {
|
||||
slots.push(ffi::Py_tp_methods, into_raw(methods));
|
||||
|
@ -200,37 +201,12 @@ where
|
|||
slots.push(ffi::Py_tp_getset, into_raw(props));
|
||||
}
|
||||
|
||||
// basic methods
|
||||
if let Some(basic) = T::basic_methods() {
|
||||
unsafe { basic.as_ref() }.update_slots(&mut slots);
|
||||
}
|
||||
// number methods
|
||||
if let Some(number) = T::number_methods() {
|
||||
unsafe { number.as_ref() }.update_slots(&mut slots);
|
||||
}
|
||||
// iterator methods
|
||||
if let Some(iter) = T::iter_methods() {
|
||||
unsafe { iter.as_ref() }.update_slots(&mut slots);
|
||||
}
|
||||
// mapping methods
|
||||
if let Some(mapping) = T::mapping_methods() {
|
||||
unsafe { mapping.as_ref() }.update_slots(&mut slots);
|
||||
}
|
||||
// sequence methods
|
||||
if let Some(sequence) = T::sequence_methods() {
|
||||
unsafe { sequence.as_ref() }.update_slots(&mut slots);
|
||||
}
|
||||
// descriptor protocol
|
||||
if let Some(descr) = T::descr_methods() {
|
||||
unsafe { descr.as_ref() }.update_slots(&mut slots);
|
||||
}
|
||||
// async methods
|
||||
if let Some(asnc) = T::async_methods() {
|
||||
unsafe { asnc.as_ref() }.update_slots(&mut slots);
|
||||
}
|
||||
// gc methods
|
||||
if let Some(gc) = T::gc_methods() {
|
||||
unsafe { gc.as_ref() }.update_slots(&mut slots);
|
||||
// protocol methods
|
||||
let mut has_gc_methods = false;
|
||||
for slot in T::get_type_slots() {
|
||||
has_gc_methods |= slot.slot == ffi::Py_tp_clear;
|
||||
has_gc_methods |= slot.slot == ffi::Py_tp_traverse;
|
||||
slots.0.push(slot);
|
||||
}
|
||||
|
||||
slots.push(0, ptr::null_mut());
|
||||
|
@ -238,7 +214,7 @@ where
|
|||
name: get_type_name::<T>(module_name)?,
|
||||
basicsize: std::mem::size_of::<T::Layout>() as c_int,
|
||||
itemsize: 0,
|
||||
flags: py_class_flags::<T>(),
|
||||
flags: py_class_flags::<T>(has_gc_methods),
|
||||
slots: slots.0.as_mut_slice().as_mut_ptr(),
|
||||
};
|
||||
|
||||
|
@ -274,10 +250,10 @@ fn tp_init_additional<T: PyClass>(type_object: *mut ffi::PyTypeObject) {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(buffer) = T::buffer_methods() {
|
||||
if let Some(buffer) = T::get_buffer() {
|
||||
unsafe {
|
||||
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer.as_ref().bf_getbuffer;
|
||||
(*(*type_object).tp_as_buffer).bf_releasebuffer = buffer.as_ref().bf_releasebuffer;
|
||||
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer.bf_getbuffer;
|
||||
(*(*type_object).tp_as_buffer).bf_releasebuffer = buffer.bf_releasebuffer;
|
||||
}
|
||||
}
|
||||
// __dict__ support
|
||||
|
@ -297,8 +273,8 @@ fn tp_init_additional<T: PyClass>(type_object: *mut ffi::PyTypeObject) {
|
|||
#[cfg(Py_LIMITED_API)]
|
||||
fn tp_init_additional<T: PyClass>(_type_object: *mut ffi::PyTypeObject) {}
|
||||
|
||||
fn py_class_flags<T: PyClass + PyTypeInfo>() -> c_uint {
|
||||
let mut flags = if T::gc_methods().is_some() || T::FLAGS & type_flags::GC != 0 {
|
||||
fn py_class_flags<T: PyClass + PyTypeInfo>(has_gc_methods: bool) -> c_uint {
|
||||
let mut flags = if has_gc_methods || T::FLAGS & type_flags::GC != 0 {
|
||||
ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HAVE_GC
|
||||
} else {
|
||||
ffi::Py_TPFLAGS_DEFAULT
|
||||
|
|
Loading…
Reference in New Issue