From eb8ff1581b8a84743c01295acd61272eafa4b93c Mon Sep 17 00:00:00 2001 From: kngwyu Date: Sat, 17 Oct 2020 16:59:56 +0900 Subject: [PATCH 1/3] Renew PyProtoMethods for new ABI3-based type construction --- src/class/basic.rs | 137 +++--- src/class/descr.rs | 36 +- src/class/gc.rs | 44 +- src/class/iter.rs | 33 +- src/class/macros.rs | 58 +-- src/class/mapping.rs | 85 ++-- src/class/number.rs | 908 ++++++++++++++++++++----------------- src/class/proto_methods.rs | 175 ++----- src/class/pyasync.rs | 49 +- src/class/sequence.rs | 142 +++--- src/pyclass.rs | 54 +-- 11 files changed, 850 insertions(+), 871 deletions(-) diff --git a/src/class/basic.rs b/src/class/basic.rs index fbcfe5a9eb0..9223b8e7f80 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -133,94 +133,109 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> { type Result: IntoPyCallbackOutput; } -/// All FFI functions for basic protocols. -#[derive(Default)] -pub struct PyObjectMethods { - pub tp_str: Option, - pub tp_repr: Option, - pub tp_hash: Option, - pub tp_getattro: Option, - pub tp_richcompare: Option, - pub tp_setattro: Option, - pub nb_bool: Option, -} - +/// Extension trait for proc-macro backend. #[doc(hidden)] -impl PyObjectMethods { - // Set functions used by `#[pyproto]`. - pub fn set_str(&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__); + ffi::PyType_Slot { + slot: ffi::Py_tp_str, + pfunc: py_unary_func!(PyObjectStrProtocol, Self::__str__) as _, + } } - pub fn set_repr(&mut self) + + fn get_repr() -> ffi::PyType_Slot where - T: for<'p> PyObjectReprProtocol<'p>, + Self: for<'p> PyObjectReprProtocol<'p>, { - self.tp_repr = py_unary_func!(PyObjectReprProtocol, T::__repr__); + ffi::PyType_Slot { + slot: ffi::Py_tp_repr, + pfunc: py_unary_func!(PyObjectReprProtocol, Self::__repr__) as _, + } } - pub fn set_hash(&mut self) + + fn get_hash() -> ffi::PyType_Slot where - T: for<'p> PyObjectHashProtocol<'p>, + Self: for<'p> PyObjectHashProtocol<'p>, { - self.tp_hash = py_unary_func!(PyObjectHashProtocol, T::__hash__, ffi::Py_hash_t); + ffi::PyType_Slot { + slot: ffi::Py_tp_hash, + pfunc: py_unary_func!(PyObjectHashProtocol, Self::__hash__, ffi::Py_hash_t) as _, + } } - pub fn set_getattr(&mut self) + + fn get_getattr() -> ffi::PyType_Slot where - T: for<'p> PyObjectGetAttrProtocol<'p>, + Self: for<'p> PyObjectGetAttrProtocol<'p>, { - self.tp_getattro = tp_getattro::(); + ffi::PyType_Slot { + slot: ffi::Py_tp_getattro, + pfunc: tp_getattro::() as _, + } } - pub fn set_richcompare(&mut self) + + fn get_richcompare() -> ffi::PyType_Slot where - T: for<'p> PyObjectRichcmpProtocol<'p>, + Self: for<'p> PyObjectRichcmpProtocol<'p>, { - self.tp_richcompare = tp_richcompare::(); + ffi::PyType_Slot { + slot: ffi::Py_tp_getattro, + pfunc: tp_richcompare::() as _, + } } - pub fn set_setattr(&mut self) + + fn get_setattr() -> ffi::PyType_Slot where - T: for<'p> PyObjectSetAttrProtocol<'p>, + Self: for<'p> PyObjectSetAttrProtocol<'p>, { - self.tp_setattro = py_func_set!(PyObjectSetAttrProtocol, T, __setattr__); + ffi::PyType_Slot { + slot: ffi::Py_tp_setattro, + pfunc: py_func_set!(PyObjectSetAttrProtocol, Self::__setattr__) as _, + } } - pub fn set_delattr(&mut self) + + fn get_delattr() -> ffi::PyType_Slot where - T: for<'p> PyObjectDelAttrProtocol<'p>, + Self: for<'p> PyObjectDelAttrProtocol<'p>, { - self.tp_setattro = py_func_del!(PyObjectDelAttrProtocol, T, __delattr__); + ffi::PyType_Slot { + slot: ffi::Py_tp_setattro, + pfunc: py_func_del!(PyObjectDelAttrProtocol, Self::__delattr__) as _, + } } - pub fn set_setdelattr(&mut self) + + fn get_setdelattr() -> ffi::PyType_Slot where - T: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>, + Self: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>, { - self.tp_setattro = py_func_set_del!( - PyObjectSetAttrProtocol, - PyObjectDelAttrProtocol, - T, - __setattr__, - __delattr__ - ) + ffi::PyType_Slot { + slot: ffi::Py_tp_setattro, + pfunc: py_func_set_del!( + PyObjectSetAttrProtocol, + PyObjectDelAttrProtocol, + Self, + __setattr__, + __delattr__ + ) as _, + } } - pub fn set_bool(&mut self) + + fn get_bool() -> ffi::PyType_Slot where - T: for<'p> PyObjectBoolProtocol<'p>, + Self: for<'p> PyObjectBoolProtocol<'p>, { - self.nb_bool = py_unary_func!(PyObjectBoolProtocol, T::__bool__, c_int); - } - - 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 _)); + ffi::PyType_Slot { + slot: ffi::Py_nb_bool, + pfunc: py_unary_func!(PyObjectBoolProtocol, Self::__bool__, c_int) as _, + } } } -fn tp_getattro() -> Option +impl<'p, T> PyBasicSlots for T where T: PyObjectProtocol<'p> {} + +fn tp_getattro() -> ffi::binaryfunc where T: for<'p> PyObjectGetAttrProtocol<'p>, { @@ -247,10 +262,10 @@ where call_ref!(slf, __getattr__, arg).convert(py) }) } - Some(wrap::) + wrap:: } -fn tp_richcompare() -> Option +fn tp_richcompare() -> ffi::richcmpfunc where T: for<'p> PyObjectRichcmpProtocol<'p>, { @@ -283,5 +298,5 @@ where slf.try_borrow()?.__richcmp__(arg, op).convert(py) }) } - Some(wrap::) + wrap:: } diff --git a/src/class/descr.rs b/src/class/descr.rs index 88fb4dc50cd..2c6a7009413 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -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, - pub tp_descr_set: Option, -} - +/// Extension trait for our proc-macro backend. #[doc(hidden)] -impl PyDescrMethods { - pub fn set_descr_get(&mut self) +pub trait PyDescrSlots { + fn get_descr_get() -> ffi::PyType_Slot where - T: for<'p> PyDescrGetProtocol<'p>, + Self: for<'p> PyDescrGetProtocol<'p>, { - self.tp_descr_get = py_ternarys_func!(PyDescrGetProtocol, T::__get__); + ffi::PyType_Slot { + slot: ffi::Py_tp_descr_get, + pfunc: py_ternarys_func!(PyDescrGetProtocol, Self::__get__) as _, + } } - pub fn set_descr_set(&mut self) + + fn get_descr_set() -> ffi::PyType_Slot where - T: for<'p> PyDescrSetProtocol<'p>, + Self: 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 _)); + ffi::PyType_Slot { + slot: ffi::Py_tp_descr_set, + pfunc: py_ternarys_func!(PyDescrSetProtocol, Self::__set__) as _, + } } } + +impl<'p, T> PyDescrSlots for T where T: PyDescrProtocol<'p> {} diff --git a/src/class/gc.rs b/src/class/gc.rs index d600e663f5b..08965df398a 100644 --- a/src/class/gc.rs +++ b/src/class/gc.rs @@ -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, - pub tp_clear: Option, -} - +/// 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(&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::(); + ffi::PyType_Slot { + slot: ffi::Py_tp_traverse, + pfunc: tp_traverse::() as _, + } } - - pub fn set_clear(&mut self) + fn get_clear() -> ffi::PyType_Slot where - T: for<'p> PyGCClearProtocol<'p>, + Self: for<'p> PyGCClearProtocol<'p>, { - self.tp_clear = tp_clear::(); + ffi::PyType_Slot { + slot: ffi::Py_tp_clear, + pfunc: tp_clear::() 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() -> Option +fn tp_traverse() -> ffi::traverseproc where T: for<'p> PyGCTraverseProtocol<'p>, { @@ -105,10 +101,10 @@ where } } - Some(tp_traverse::) + tp_traverse:: } -fn tp_clear() -> Option +fn tp_clear() -> ffi::inquiry where T: for<'p> PyGCClearProtocol<'p>, { @@ -123,5 +119,5 @@ where slf.borrow_mut().__clear__(); 0 } - Some(tp_clear::) + tp_clear:: } diff --git a/src/class/iter.rs b/src/class/iter.rs index 9f5ffc0d260..e53dcc97638 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -71,32 +71,31 @@ pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> { type Result: IntoPyCallbackOutput; } -#[derive(Default)] -pub struct PyIterMethods { - pub tp_iter: Option, - pub tp_iternext: Option, -} - +/// Extension trait for proc-macro backend. #[doc(hidden)] -impl PyIterMethods { - pub fn set_iter(&mut self) +pub trait PyIterSlots { + fn get_iter() -> ffi::PyType_Slot where - T: for<'p> PyIterIterProtocol<'p>, + Self: for<'p> PyIterIterProtocol<'p>, { - self.tp_iter = py_unarys_func!(PyIterIterProtocol, T::__iter__); + ffi::PyType_Slot { + slot: ffi::Py_tp_iter, + pfunc: py_unarys_func!(PyIterIterProtocol, Self::__iter__) as _, + } } - pub fn set_iternext(&mut self) + fn get_iternext() -> ffi::PyType_Slot where - T: for<'p> PyIterNextProtocol<'p>, + Self: 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 _)); + ffi::PyType_Slot { + slot: ffi::Py_tp_iternext, + pfunc: py_unarys_func!(PyIterNextProtocol, Self::__next__) 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. /// diff --git a/src/class/macros.rs b/src/class/macros.rs index 49db13c775b..98c0a47da74 100644 --- a/src/class/macros.rs +++ b/src/class/macros.rs @@ -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 { >::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 = 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 = 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::) + 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( 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>(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( + ($trait_name:ident, $class:ident :: $fn_del:ident) => {{ + unsafe extern "C" fn wrap( 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>(slf); + let slf = py.from_borrowed_ptr::<$crate::PyCell>(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( 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>(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> }}; } diff --git a/src/class/mapping.rs b/src/class/mapping.rs index c9daa7bd9c2..07ee4122262 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -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, - pub mp_subscript: Option, - pub mp_ass_subscript: Option, -} - -#[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; } +/// Extension trait for proc-macro backend. #[doc(hidden)] -impl PyMappingMethods { - pub fn set_length(&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(&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(&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(&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(&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> {} diff --git a/src/class/number.rs b/src/class/number.rs index 60f7d17eb6a..b095da9a777 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -5,97 +5,6 @@ use crate::callback::IntoPyCallbackOutput; use crate::err::PyErr; use crate::{ffi, FromPyObject, PyClass, PyObject}; -#[cfg(Py_LIMITED_API)] -use std::os::raw::c_void; - -#[cfg(Py_LIMITED_API)] -#[derive(Clone)] -pub struct PyNumberMethods { - pub nb_add: Option, - pub nb_subtract: Option, - pub nb_multiply: Option, - pub nb_remainder: Option, - pub nb_divmod: Option, - pub nb_power: Option, - pub nb_negative: Option, - pub nb_positive: Option, - pub nb_absolute: Option, - pub nb_bool: Option, - pub nb_invert: Option, - pub nb_lshift: Option, - pub nb_rshift: Option, - pub nb_and: Option, - pub nb_xor: Option, - pub nb_or: Option, - pub nb_int: Option, - #[allow(dead_code)] - pub nb_reserved: *mut c_void, - pub nb_float: Option, - pub nb_inplace_add: Option, - pub nb_inplace_subtract: Option, - pub nb_inplace_multiply: Option, - pub nb_inplace_remainder: Option, - pub nb_inplace_power: Option, - pub nb_inplace_lshift: Option, - pub nb_inplace_rshift: Option, - pub nb_inplace_and: Option, - pub nb_inplace_xor: Option, - pub nb_inplace_or: Option, - pub nb_floor_divide: Option, - pub nb_true_divide: Option, - pub nb_inplace_floor_divide: Option, - pub nb_inplace_true_divide: Option, - pub nb_index: Option, - pub nb_matrix_multiply: Option, - pub nb_inplace_matrix_multiply: Option, -} - -#[cfg(not(Py_LIMITED_API))] -pub use crate::ffi::PyNumberMethods; - -impl Default for PyNumberMethods { - #[inline] - fn default() -> Self { - Self { - nb_add: None, - nb_subtract: None, - nb_multiply: None, - nb_remainder: None, - nb_divmod: None, - nb_power: None, - nb_negative: None, - nb_positive: None, - nb_absolute: None, - nb_bool: None, - nb_invert: None, - nb_lshift: None, - nb_rshift: None, - nb_and: None, - nb_xor: None, - nb_or: None, - nb_int: None, - nb_reserved: ::std::ptr::null_mut(), - nb_float: None, - nb_inplace_add: None, - nb_inplace_subtract: None, - nb_inplace_multiply: None, - nb_inplace_remainder: None, - nb_inplace_power: None, - nb_inplace_lshift: None, - nb_inplace_rshift: None, - nb_inplace_and: None, - nb_inplace_xor: None, - nb_inplace_or: None, - nb_floor_divide: None, - nb_true_divide: None, - nb_inplace_floor_divide: None, - nb_inplace_true_divide: None, - nb_index: None, - nb_matrix_multiply: None, - nb_inplace_matrix_multiply: None, - } - } -} /// Number interface #[allow(unused_variables)] @@ -669,111 +578,164 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> { type Result: IntoPyCallbackOutput; } +/// Extension trait for proc-macro backend. #[doc(hidden)] -impl PyNumberMethods { - pub fn set_add_radd(&mut self) - where - T: for<'p> PyNumberAddProtocol<'p> + for<'p> PyNumberRAddProtocol<'p>, - { - self.nb_add = py_binary_fallback_num_func!( - T, - PyNumberAddProtocol::__add__, - PyNumberRAddProtocol::__radd__ - ); +pub trait PyNumberSlots { + fn get_add_radd() -> ffi::PyType_Slot + where + Self: for<'p> PyNumberAddProtocol<'p> + for<'p> PyNumberRAddProtocol<'p>, + { + ffi::PyType_Slot { + slot: ffi::Py_nb_add, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberAddProtocol::__add__, + PyNumberRAddProtocol::__radd__ + ) as _, + } } - pub fn set_add(&mut self) + + fn get_add() -> ffi::PyType_Slot where - T: for<'p> PyNumberAddProtocol<'p>, + Self: for<'p> PyNumberAddProtocol<'p>, { - self.nb_add = py_binary_num_func!(PyNumberAddProtocol, T::__add__); + ffi::PyType_Slot { + slot: ffi::Py_nb_add, + pfunc: py_binary_num_func!(PyNumberAddProtocol, Self::__add__) as _, + } } - pub fn set_radd(&mut self) + + fn get_radd() -> ffi::PyType_Slot where - T: for<'p> PyNumberRAddProtocol<'p>, + Self: for<'p> PyNumberRAddProtocol<'p>, { - self.nb_add = py_binary_reversed_num_func!(PyNumberRAddProtocol, T::__radd__); + ffi::PyType_Slot { + slot: ffi::Py_nb_add, + pfunc: py_binary_reversed_num_func!(PyNumberRAddProtocol, Self::__radd__) as _, + } } - pub fn set_sub_rsub(&mut self) + + fn get_sub_rsub() -> ffi::PyType_Slot where - T: for<'p> PyNumberSubProtocol<'p> + for<'p> PyNumberRSubProtocol<'p>, + Self: for<'p> PyNumberSubProtocol<'p> + for<'p> PyNumberRSubProtocol<'p>, { - self.nb_subtract = py_binary_fallback_num_func!( - T, - PyNumberSubProtocol::__sub__, - PyNumberRSubProtocol::__rsub__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_subtract, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberSubProtocol::__sub__, + PyNumberRSubProtocol::__rsub__ + ) as _, + } } - pub fn set_sub(&mut self) + + fn get_sub() -> ffi::PyType_Slot where - T: for<'p> PyNumberSubProtocol<'p>, + Self: for<'p> PyNumberSubProtocol<'p>, { - self.nb_subtract = py_binary_num_func!(PyNumberSubProtocol, T::__sub__); + ffi::PyType_Slot { + slot: ffi::Py_nb_subtract, + pfunc: py_binary_num_func!(PyNumberSubProtocol, Self::__sub__) as _, + } } - pub fn set_rsub(&mut self) + + fn get_rsub() -> ffi::PyType_Slot where - T: for<'p> PyNumberRSubProtocol<'p>, + Self: for<'p> PyNumberRSubProtocol<'p>, { - self.nb_subtract = py_binary_reversed_num_func!(PyNumberRSubProtocol, T::__rsub__); + ffi::PyType_Slot { + slot: ffi::Py_nb_subtract, + pfunc: py_binary_reversed_num_func!(PyNumberRSubProtocol, Self::__rsub__) as _, + } } - pub fn set_mul_rmul(&mut self) + + fn get_mul_rmul() -> ffi::PyType_Slot where - T: for<'p> PyNumberMulProtocol<'p> + for<'p> PyNumberRMulProtocol<'p>, + Self: for<'p> PyNumberMulProtocol<'p> + for<'p> PyNumberRMulProtocol<'p>, { - self.nb_multiply = py_binary_fallback_num_func!( - T, - PyNumberMulProtocol::__mul__, - PyNumberRMulProtocol::__rmul__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_multiply, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberMulProtocol::__mul__, + PyNumberRMulProtocol::__rmul__ + ) as _, + } } - pub fn set_mul(&mut self) + + fn get_mul() -> ffi::PyType_Slot where - T: for<'p> PyNumberMulProtocol<'p>, + Self: for<'p> PyNumberMulProtocol<'p>, { - self.nb_multiply = py_binary_num_func!(PyNumberMulProtocol, T::__mul__); + ffi::PyType_Slot { + slot: ffi::Py_nb_multiply, + pfunc: py_binary_num_func!(PyNumberMulProtocol, Self::__mul__) as _, + } } - pub fn set_rmul(&mut self) + + fn get_rmul() -> ffi::PyType_Slot where - T: for<'p> PyNumberRMulProtocol<'p>, + Self: for<'p> PyNumberRMulProtocol<'p>, { - self.nb_multiply = py_binary_reversed_num_func!(PyNumberRMulProtocol, T::__rmul__); + ffi::PyType_Slot { + slot: ffi::Py_nb_multiply, + pfunc: py_binary_reversed_num_func!(PyNumberRMulProtocol, Self::__rmul__) as _, + } } - pub fn set_mod(&mut self) + + fn get_mod() -> ffi::PyType_Slot where - T: for<'p> PyNumberModProtocol<'p>, + Self: for<'p> PyNumberModProtocol<'p>, { - self.nb_remainder = py_binary_num_func!(PyNumberModProtocol, T::__mod__); + ffi::PyType_Slot { + slot: ffi::Py_nb_remainder, + pfunc: py_binary_num_func!(PyNumberModProtocol, Self::__mod__) as _, + } } - pub fn set_divmod_rdivmod(&mut self) + + fn get_divmod_rdivmod() -> ffi::PyType_Slot where - T: for<'p> PyNumberDivmodProtocol<'p> + for<'p> PyNumberRDivmodProtocol<'p>, + Self: for<'p> PyNumberDivmodProtocol<'p> + for<'p> PyNumberRDivmodProtocol<'p>, { - self.nb_divmod = py_binary_fallback_num_func!( - T, - PyNumberDivmodProtocol::__divmod__, - PyNumberRDivmodProtocol::__rdivmod__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_divmod, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberDivmodProtocol::__divmod__, + PyNumberRDivmodProtocol::__rdivmod__ + ) as _, + } } - pub fn set_divmod(&mut self) + + fn get_divmod() -> ffi::PyType_Slot where - T: for<'p> PyNumberDivmodProtocol<'p>, + Self: for<'p> PyNumberDivmodProtocol<'p>, { - self.nb_divmod = py_binary_num_func!(PyNumberDivmodProtocol, T::__divmod__); + ffi::PyType_Slot { + slot: ffi::Py_nb_divmod, + pfunc: py_binary_num_func!(PyNumberDivmodProtocol, Self::__divmod__) as _, + } } - pub fn set_rdivmod(&mut self) + + fn get_rdivmod() -> ffi::PyType_Slot where - T: for<'p> PyNumberRDivmodProtocol<'p>, + Self: for<'p> PyNumberRDivmodProtocol<'p>, { - self.nb_divmod = py_binary_reversed_num_func!(PyNumberRDivmodProtocol, T::__rdivmod__); + ffi::PyType_Slot { + slot: ffi::Py_nb_divmod, + pfunc: py_binary_reversed_num_func!(PyNumberRDivmodProtocol, Self::__rdivmod__) as _, + } } - pub fn set_pow_rpow(&mut self) + + fn get_pow_rpow() -> ffi::PyType_Slot where - T: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>, + Self: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>, { unsafe extern "C" fn wrap_pow_and_rpow( - lhs: *mut crate::ffi::PyObject, - rhs: *mut crate::ffi::PyObject, - modulo: *mut crate::ffi::PyObject, - ) -> *mut crate::ffi::PyObject + lhs: *mut ffi::PyObject, + rhs: *mut ffi::PyObject, + modulo: *mut ffi::PyObject, + ) -> *mut ffi::PyObject where T: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>, { @@ -794,17 +756,22 @@ impl PyNumberMethods { } }) } - self.nb_power = Some(wrap_pow_and_rpow::); + + ffi::PyType_Slot { + slot: ffi::Py_nb_power, + pfunc: wrap_pow_and_rpow:: as _, + } } - pub fn set_pow(&mut self) + + fn get_pow() -> ffi::PyType_Slot where - T: for<'p> PyNumberPowProtocol<'p>, + Self: for<'p> PyNumberPowProtocol<'p>, { unsafe extern "C" fn wrap_pow( - lhs: *mut crate::ffi::PyObject, - rhs: *mut crate::ffi::PyObject, - modulo: *mut crate::ffi::PyObject, - ) -> *mut crate::ffi::PyObject + lhs: *mut ffi::PyObject, + rhs: *mut ffi::PyObject, + modulo: *mut ffi::PyObject, + ) -> *mut ffi::PyObject where T: for<'p> PyNumberPowProtocol<'p>, { @@ -815,17 +782,22 @@ impl PyNumberMethods { T::__pow__(lhs, rhs, modulo).convert(py) }) } - self.nb_power = Some(wrap_pow::); + + ffi::PyType_Slot { + slot: ffi::Py_nb_power, + pfunc: wrap_pow:: as _, + } } - pub fn set_rpow(&mut self) + + fn get_rpow() -> ffi::PyType_Slot where - T: for<'p> PyNumberRPowProtocol<'p>, + Self: for<'p> PyNumberRPowProtocol<'p>, { unsafe extern "C" fn wrap_rpow( - arg: *mut crate::ffi::PyObject, - slf: *mut crate::ffi::PyObject, - modulo: *mut crate::ffi::PyObject, - ) -> *mut crate::ffi::PyObject + arg: *mut ffi::PyObject, + slf: *mut ffi::PyObject, + modulo: *mut ffi::PyObject, + ) -> *mut ffi::PyObject where T: for<'p> PyNumberRPowProtocol<'p>, { @@ -836,189 +808,294 @@ impl PyNumberMethods { slf.try_borrow()?.__rpow__(arg, modulo).convert(py) }) } - self.nb_power = Some(wrap_rpow::); + + ffi::PyType_Slot { + slot: ffi::Py_nb_power, + pfunc: wrap_rpow:: as _, + } } - pub fn set_neg(&mut self) + + fn get_neg() -> ffi::PyType_Slot where - T: for<'p> PyNumberNegProtocol<'p>, + Self: for<'p> PyNumberNegProtocol<'p>, { - self.nb_negative = py_unary_func!(PyNumberNegProtocol, T::__neg__); + ffi::PyType_Slot { + slot: ffi::Py_nb_negative, + pfunc: py_unary_func!(PyNumberNegProtocol, Self::__neg__) as _, + } } - pub fn set_pos(&mut self) + + fn get_pos() -> ffi::PyType_Slot where - T: for<'p> PyNumberPosProtocol<'p>, + Self: for<'p> PyNumberPosProtocol<'p>, { - self.nb_positive = py_unary_func!(PyNumberPosProtocol, T::__pos__); + ffi::PyType_Slot { + slot: ffi::Py_nb_absolute, + pfunc: py_unary_func!(PyNumberPosProtocol, Self::__pos__) as _, + } } - pub fn set_abs(&mut self) + + fn get_abs() -> ffi::PyType_Slot where - T: for<'p> PyNumberAbsProtocol<'p>, + Self: for<'p> PyNumberAbsProtocol<'p>, { - self.nb_absolute = py_unary_func!(PyNumberAbsProtocol, T::__abs__); + ffi::PyType_Slot { + slot: ffi::Py_nb_absolute, + pfunc: py_unary_func!(PyNumberAbsProtocol, Self::__abs__) as _, + } } - pub fn set_invert(&mut self) + + fn get_invert() -> ffi::PyType_Slot where - T: for<'p> PyNumberInvertProtocol<'p>, + Self: for<'p> PyNumberInvertProtocol<'p>, { - self.nb_invert = py_unary_func!(PyNumberInvertProtocol, T::__invert__); + ffi::PyType_Slot { + slot: ffi::Py_nb_invert, + pfunc: py_unary_func!(PyNumberInvertProtocol, Self::__invert__) as _, + } } - pub fn set_lshift_rlshift(&mut self) + + fn get_lshift_rlshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberLShiftProtocol<'p> + for<'p> PyNumberRLShiftProtocol<'p>, + Self: for<'p> PyNumberLShiftProtocol<'p> + for<'p> PyNumberRLShiftProtocol<'p>, { - self.nb_lshift = py_binary_fallback_num_func!( - T, - PyNumberLShiftProtocol::__lshift__, - PyNumberRLShiftProtocol::__rlshift__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_lshift, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberLShiftProtocol::__lshift__, + PyNumberRLShiftProtocol::__rlshift__ + ) as _, + } } - pub fn set_lshift(&mut self) + + fn get_lshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberLShiftProtocol<'p>, + Self: for<'p> PyNumberLShiftProtocol<'p>, { - self.nb_lshift = py_binary_num_func!(PyNumberLShiftProtocol, T::__lshift__); + ffi::PyType_Slot { + slot: ffi::Py_nb_lshift, + pfunc: py_binary_num_func!(PyNumberLShiftProtocol, Self::__lshift__) as _, + } } - pub fn set_rlshift(&mut self) + + fn get_rlshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberRLShiftProtocol<'p>, + Self: for<'p> PyNumberRLShiftProtocol<'p>, { - self.nb_lshift = py_binary_reversed_num_func!(PyNumberRLShiftProtocol, T::__rlshift__); + ffi::PyType_Slot { + slot: ffi::Py_nb_lshift, + pfunc: py_binary_reversed_num_func!(PyNumberRLShiftProtocol, Self::__rlshift__) as _, + } } - pub fn set_rshift_rrshift(&mut self) + + fn get_rshift_rrshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberRShiftProtocol<'p> + for<'p> PyNumberRRShiftProtocol<'p>, + Self: for<'p> PyNumberRShiftProtocol<'p> + for<'p> PyNumberRRShiftProtocol<'p>, { - self.nb_rshift = py_binary_fallback_num_func!( - T, - PyNumberRShiftProtocol::__rshift__, - PyNumberRRShiftProtocol::__rrshift__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_rshift, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberRShiftProtocol::__rshift__, + PyNumberRRShiftProtocol::__rrshift__ + ) as _, + } } - pub fn set_rshift(&mut self) + + fn get_rshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberRShiftProtocol<'p>, + Self: for<'p> PyNumberRShiftProtocol<'p>, { - self.nb_rshift = py_binary_num_func!(PyNumberRShiftProtocol, T::__rshift__); + ffi::PyType_Slot { + slot: ffi::Py_nb_rshift, + pfunc: py_binary_num_func!(PyNumberRShiftProtocol, Self::__rshift__) as _, + } } - pub fn set_rrshift(&mut self) + + fn get_rrshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberRRShiftProtocol<'p>, + Self: for<'p> PyNumberRRShiftProtocol<'p>, { - self.nb_rshift = py_binary_reversed_num_func!(PyNumberRRShiftProtocol, T::__rrshift__); + ffi::PyType_Slot { + slot: ffi::Py_nb_rshift, + pfunc: py_binary_reversed_num_func!(PyNumberRRShiftProtocol, Self::__rrshift__) as _, + } } - pub fn set_and_rand(&mut self) + + fn get_and_rand() -> ffi::PyType_Slot where - T: for<'p> PyNumberAndProtocol<'p> + for<'p> PyNumberRAndProtocol<'p>, + Self: for<'p> PyNumberAndProtocol<'p> + for<'p> PyNumberRAndProtocol<'p>, { - self.nb_and = py_binary_fallback_num_func!( - T, - PyNumberAndProtocol::__and__, - PyNumberRAndProtocol::__rand__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_and, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberAndProtocol::__and__, + PyNumberRAndProtocol::__rand__ + ) as _, + } } - pub fn set_and(&mut self) + + fn get_and() -> ffi::PyType_Slot where - T: for<'p> PyNumberAndProtocol<'p>, + Self: for<'p> PyNumberAndProtocol<'p>, { - self.nb_and = py_binary_num_func!(PyNumberAndProtocol, T::__and__); + ffi::PyType_Slot { + slot: ffi::Py_nb_and, + pfunc: py_binary_num_func!(PyNumberAndProtocol, Self::__and__) as _, + } } - pub fn set_rand(&mut self) + + fn get_rand() -> ffi::PyType_Slot where - T: for<'p> PyNumberRAndProtocol<'p>, + Self: for<'p> PyNumberRAndProtocol<'p>, { - self.nb_and = py_binary_reversed_num_func!(PyNumberRAndProtocol, T::__rand__); + ffi::PyType_Slot { + slot: ffi::Py_nb_and, + pfunc: py_binary_reversed_num_func!(PyNumberRAndProtocol, Self::__rand__) as _, + } } - pub fn set_xor_rxor(&mut self) + + fn get_xor_rxor() -> ffi::PyType_Slot where - T: for<'p> PyNumberXorProtocol<'p> + for<'p> PyNumberRXorProtocol<'p>, + Self: for<'p> PyNumberXorProtocol<'p> + for<'p> PyNumberRXorProtocol<'p>, { - self.nb_xor = py_binary_fallback_num_func!( - T, - PyNumberXorProtocol::__xor__, - PyNumberRXorProtocol::__rxor__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_xor, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberXorProtocol::__xor__, + PyNumberRXorProtocol::__rxor__ + ) as _, + } } - pub fn set_xor(&mut self) + + fn get_xor() -> ffi::PyType_Slot where - T: for<'p> PyNumberXorProtocol<'p>, + Self: for<'p> PyNumberXorProtocol<'p>, { - self.nb_xor = py_binary_num_func!(PyNumberXorProtocol, T::__xor__); + ffi::PyType_Slot { + slot: ffi::Py_nb_xor, + pfunc: py_binary_num_func!(PyNumberXorProtocol, Self::__xor__) as _, + } } - pub fn set_rxor(&mut self) + + fn get_rxor() -> ffi::PyType_Slot where - T: for<'p> PyNumberRXorProtocol<'p>, + Self: for<'p> PyNumberRXorProtocol<'p>, { - self.nb_xor = py_binary_reversed_num_func!(PyNumberRXorProtocol, T::__rxor__); + ffi::PyType_Slot { + slot: ffi::Py_nb_xor, + pfunc: py_binary_reversed_num_func!(PyNumberRXorProtocol, Self::__rxor__) as _, + } } - pub fn set_or_ror(&mut self) + + fn get_or_ror() -> ffi::PyType_Slot where - T: for<'p> PyNumberOrProtocol<'p> + for<'p> PyNumberROrProtocol<'p>, + Self: for<'p> PyNumberOrProtocol<'p> + for<'p> PyNumberROrProtocol<'p>, { - self.nb_or = py_binary_fallback_num_func!( - T, - PyNumberOrProtocol::__or__, - PyNumberROrProtocol::__ror__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_or, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberOrProtocol::__or__, + PyNumberROrProtocol::__ror__ + ) as _, + } } - pub fn set_or(&mut self) + + fn get_or() -> ffi::PyType_Slot where - T: for<'p> PyNumberOrProtocol<'p>, + Self: for<'p> PyNumberOrProtocol<'p>, { - self.nb_or = py_binary_num_func!(PyNumberOrProtocol, T::__or__); + ffi::PyType_Slot { + slot: ffi::Py_nb_or, + pfunc: py_binary_num_func!(PyNumberOrProtocol, Self::__or__) as _, + } } - pub fn set_ror(&mut self) + + fn get_ror() -> ffi::PyType_Slot where - T: for<'p> PyNumberROrProtocol<'p>, + Self: for<'p> PyNumberROrProtocol<'p>, { - self.nb_or = py_binary_reversed_num_func!(PyNumberROrProtocol, T::__ror__); + ffi::PyType_Slot { + slot: ffi::Py_nb_or, + pfunc: py_binary_reversed_num_func!(PyNumberROrProtocol, Self::__ror__) as _, + } } - pub fn set_int(&mut self) + + fn get_int() -> ffi::PyType_Slot where - T: for<'p> PyNumberIntProtocol<'p>, + Self: for<'p> PyNumberIntProtocol<'p>, { - self.nb_int = py_unary_func!(PyNumberIntProtocol, T::__int__); + ffi::PyType_Slot { + slot: ffi::Py_nb_int, + pfunc: py_unary_func!(PyNumberIntProtocol, Self::__int__) as _, + } } - pub fn set_float(&mut self) + + fn get_float() -> ffi::PyType_Slot where - T: for<'p> PyNumberFloatProtocol<'p>, + Self: for<'p> PyNumberFloatProtocol<'p>, { - self.nb_float = py_unary_func!(PyNumberFloatProtocol, T::__float__); + ffi::PyType_Slot { + slot: ffi::Py_nb_float, + pfunc: py_unary_func!(PyNumberFloatProtocol, Self::__float__) as _, + } } - pub fn set_iadd(&mut self) + + fn get_iadd() -> ffi::PyType_Slot where - T: for<'p> PyNumberIAddProtocol<'p>, + Self: for<'p> PyNumberIAddProtocol<'p>, { - self.nb_inplace_add = py_binary_self_func!(PyNumberIAddProtocol, T::__iadd__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_add, + pfunc: py_binary_self_func!(PyNumberIAddProtocol, Self::__iadd__) as _, + } } - pub fn set_isub(&mut self) + + fn get_isub() -> ffi::PyType_Slot where - T: for<'p> PyNumberISubProtocol<'p>, + Self: for<'p> PyNumberISubProtocol<'p>, { - self.nb_inplace_subtract = py_binary_self_func!(PyNumberISubProtocol, T::__isub__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_subtract, + pfunc: py_binary_self_func!(PyNumberISubProtocol, Self::__isub__) as _, + } } - pub fn set_imul(&mut self) + + fn get_imul() -> ffi::PyType_Slot where - T: for<'p> PyNumberIMulProtocol<'p>, + Self: for<'p> PyNumberIMulProtocol<'p>, { - self.nb_inplace_multiply = py_binary_self_func!(PyNumberIMulProtocol, T::__imul__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_multiply, + pfunc: py_binary_self_func!(PyNumberIMulProtocol, Self::__imul__) as _, + } } - pub fn set_imod(&mut self) + + fn get_imod() -> ffi::PyType_Slot where - T: for<'p> PyNumberIModProtocol<'p>, + Self: for<'p> PyNumberIModProtocol<'p>, { - self.nb_inplace_remainder = py_binary_self_func!(PyNumberIModProtocol, T::__imod__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_remainder, + pfunc: py_binary_self_func!(PyNumberIModProtocol, Self::__imod__) as _, + } } - pub fn set_ipow(&mut self) + + fn get_ipow() -> ffi::PyType_Slot where - T: for<'p> PyNumberIPowProtocol<'p>, + Self: for<'p> PyNumberIPowProtocol<'p>, { // NOTE: Somehow __ipow__ causes SIGSEGV in Python < 3.8 when we extract, // so we ignore it. It's the same as what CPython does. unsafe extern "C" fn wrap_ipow( - slf: *mut crate::ffi::PyObject, - other: *mut crate::ffi::PyObject, - _modulo: *mut crate::ffi::PyObject, - ) -> *mut crate::ffi::PyObject + slf: *mut ffi::PyObject, + other: *mut ffi::PyObject, + _modulo: *mut ffi::PyObject, + ) -> *mut ffi::PyObject where T: for<'p> PyNumberIPowProtocol<'p>, { @@ -1030,202 +1107,205 @@ impl PyNumberMethods { Ok::<_, PyErr>(slf) }) } - self.nb_inplace_power = Some(wrap_ipow::); + + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_power, + pfunc: wrap_ipow:: as _, + } } - pub fn set_ilshift(&mut self) + + fn get_ilshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberILShiftProtocol<'p>, + Self: for<'p> PyNumberILShiftProtocol<'p>, { - self.nb_inplace_lshift = py_binary_self_func!(PyNumberILShiftProtocol, T::__ilshift__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_lshift, + pfunc: py_binary_self_func!(PyNumberILShiftProtocol, Self::__ilshift__) as _, + } } - pub fn set_irshift(&mut self) + + fn get_irshift() -> ffi::PyType_Slot where - T: for<'p> PyNumberIRShiftProtocol<'p>, + Self: for<'p> PyNumberIRShiftProtocol<'p>, { - self.nb_inplace_rshift = py_binary_self_func!(PyNumberIRShiftProtocol, T::__irshift__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_rshift, + pfunc: py_binary_self_func!(PyNumberIRShiftProtocol, Self::__irshift__) as _, + } } - pub fn set_iand(&mut self) + + fn get_iand() -> ffi::PyType_Slot where - T: for<'p> PyNumberIAndProtocol<'p>, + Self: for<'p> PyNumberIAndProtocol<'p>, { - self.nb_inplace_and = py_binary_self_func!(PyNumberIAndProtocol, T::__iand__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_and, + pfunc: py_binary_self_func!(PyNumberIAndProtocol, Self::__iand__) as _, + } } - pub fn set_ixor(&mut self) + + fn get_ixor() -> ffi::PyType_Slot where - T: for<'p> PyNumberIXorProtocol<'p>, + Self: for<'p> PyNumberIXorProtocol<'p>, { - self.nb_inplace_xor = py_binary_self_func!(PyNumberIXorProtocol, T::__ixor__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_xor, + pfunc: py_binary_self_func!(PyNumberIXorProtocol, Self::__ixor__) as _, + } } - pub fn set_ior(&mut self) + + fn get_ior() -> ffi::PyType_Slot where - T: for<'p> PyNumberIOrProtocol<'p>, + Self: for<'p> PyNumberIOrProtocol<'p>, { - self.nb_inplace_or = py_binary_self_func!(PyNumberIOrProtocol, T::__ior__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_or, + pfunc: py_binary_self_func!(PyNumberIOrProtocol, Self::__ior__) as _, + } } - pub fn set_floordiv_rfloordiv(&mut self) + + fn get_floordiv_rfloordiv() -> ffi::PyType_Slot where - T: for<'p> PyNumberFloordivProtocol<'p> + for<'p> PyNumberRFloordivProtocol<'p>, + Self: for<'p> PyNumberFloordivProtocol<'p> + for<'p> PyNumberRFloordivProtocol<'p>, { - self.nb_floor_divide = py_binary_fallback_num_func!( - T, - PyNumberFloordivProtocol::__floordiv__, - PyNumberRFloordivProtocol::__rfloordiv__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_floor_divide, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberFloordivProtocol::__floordiv__, + PyNumberRFloordivProtocol::__rfloordiv__ + ) as _, + } } - pub fn set_floordiv(&mut self) + + fn get_floordiv() -> ffi::PyType_Slot where - T: for<'p> PyNumberFloordivProtocol<'p>, + Self: for<'p> PyNumberFloordivProtocol<'p>, { - self.nb_floor_divide = py_binary_num_func!(PyNumberFloordivProtocol, T::__floordiv__); + ffi::PyType_Slot { + slot: ffi::Py_nb_floor_divide, + pfunc: py_binary_num_func!(PyNumberFloordivProtocol, Self::__floordiv__) as _, + } } - pub fn set_rfloordiv(&mut self) + + fn get_rfloordiv() -> ffi::PyType_Slot where - T: for<'p> PyNumberRFloordivProtocol<'p>, + Self: for<'p> PyNumberRFloordivProtocol<'p>, { - self.nb_floor_divide = - py_binary_reversed_num_func!(PyNumberRFloordivProtocol, T::__rfloordiv__); + ffi::PyType_Slot { + slot: ffi::Py_nb_floor_divide, + pfunc: py_binary_reversed_num_func!(PyNumberRFloordivProtocol, Self::__rfloordiv__) + as _, + } } - pub fn set_truediv_rtruediv(&mut self) + + fn get_truediv_rtruediv() -> ffi::PyType_Slot where - T: for<'p> PyNumberTruedivProtocol<'p> + for<'p> PyNumberRTruedivProtocol<'p>, + Self: for<'p> PyNumberTruedivProtocol<'p> + for<'p> PyNumberRTruedivProtocol<'p>, { - self.nb_true_divide = py_binary_fallback_num_func!( - T, - PyNumberTruedivProtocol::__truediv__, - PyNumberRTruedivProtocol::__rtruediv__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_true_divide, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberTruedivProtocol::__truediv__, + PyNumberRTruedivProtocol::__rtruediv__ + ) as _, + } } - pub fn set_truediv(&mut self) + + fn get_truediv() -> ffi::PyType_Slot where - T: for<'p> PyNumberTruedivProtocol<'p>, + Self: for<'p> PyNumberTruedivProtocol<'p>, { - self.nb_true_divide = py_binary_num_func!(PyNumberTruedivProtocol, T::__truediv__); + ffi::PyType_Slot { + slot: ffi::Py_nb_true_divide, + pfunc: py_binary_num_func!(PyNumberTruedivProtocol, Self::__truediv__) as _, + } } - pub fn set_rtruediv(&mut self) + + fn get_rtruediv() -> ffi::PyType_Slot where - T: for<'p> PyNumberRTruedivProtocol<'p>, + Self: for<'p> PyNumberRTruedivProtocol<'p>, { - self.nb_true_divide = - py_binary_reversed_num_func!(PyNumberRTruedivProtocol, T::__rtruediv__); + ffi::PyType_Slot { + slot: ffi::Py_nb_true_divide, + pfunc: py_binary_reversed_num_func!(PyNumberRTruedivProtocol, Self::__rtruediv__) as _, + } } - pub fn set_ifloordiv(&mut self) + + fn get_ifloordiv() -> ffi::PyType_Slot where - T: for<'p> PyNumberIFloordivProtocol<'p>, + Self: for<'p> PyNumberIFloordivProtocol<'p>, { - self.nb_inplace_floor_divide = - py_binary_self_func!(PyNumberIFloordivProtocol, T::__ifloordiv__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_floor_divide, + pfunc: py_binary_self_func!(PyNumberIFloordivProtocol, Self::__ifloordiv__) as _, + } } - pub fn set_itruediv(&mut self) + + fn get_itruediv() -> ffi::PyType_Slot where - T: for<'p> PyNumberITruedivProtocol<'p>, + Self: for<'p> PyNumberITruedivProtocol<'p>, { - self.nb_inplace_true_divide = - py_binary_self_func!(PyNumberITruedivProtocol, T::__itruediv__); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_true_divide, + pfunc: py_binary_self_func!(PyNumberITruedivProtocol, Self::__itruediv__) as _, + } } - pub fn set_index(&mut self) + + fn get_index() -> ffi::PyType_Slot where - T: for<'p> PyNumberIndexProtocol<'p>, + Self: for<'p> PyNumberIndexProtocol<'p>, { - self.nb_index = py_unary_func!(PyNumberIndexProtocol, T::__index__); + ffi::PyType_Slot { + slot: ffi::Py_nb_index, + pfunc: py_unary_func!(PyNumberIndexProtocol, Self::__index__) as _, + } } - pub fn set_matmul_rmatmul(&mut self) + + fn get_matmul_rmatmul() -> ffi::PyType_Slot where - T: for<'p> PyNumberMatmulProtocol<'p> + for<'p> PyNumberRMatmulProtocol<'p>, + Self: for<'p> PyNumberMatmulProtocol<'p> + for<'p> PyNumberRMatmulProtocol<'p>, { - self.nb_matrix_multiply = py_binary_fallback_num_func!( - T, - PyNumberMatmulProtocol::__matmul__, - PyNumberRMatmulProtocol::__rmatmul__ - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_matrix_multiply, + pfunc: py_binary_fallback_num_func!( + Self, + PyNumberMatmulProtocol::__matmul__, + PyNumberRMatmulProtocol::__rmatmul__ + ) as _, + } } - pub fn set_matmul(&mut self) + + fn get_matmul() -> ffi::PyType_Slot where - T: for<'p> PyNumberMatmulProtocol<'p>, + Self: for<'p> PyNumberMatmulProtocol<'p>, { - self.nb_matrix_multiply = py_binary_num_func!(PyNumberMatmulProtocol, T::__matmul__); + ffi::PyType_Slot { + slot: ffi::Py_nb_matrix_multiply, + pfunc: py_binary_num_func!(PyNumberMatmulProtocol, Self::__matmul__) as _, + } } - pub fn set_rmatmul(&mut self) + + fn get_rmatmul() -> ffi::PyType_Slot where - T: for<'p> PyNumberRMatmulProtocol<'p>, + Self: for<'p> PyNumberRMatmulProtocol<'p>, { - self.nb_matrix_multiply = - py_binary_reversed_num_func!(PyNumberRMatmulProtocol, T::__rmatmul__); + ffi::PyType_Slot { + slot: ffi::Py_nb_matrix_multiply, + pfunc: py_binary_reversed_num_func!(PyNumberRMatmulProtocol, Self::__rmatmul__) as _, + } } - pub fn set_imatmul(&mut self) + + fn get_imatmul() -> ffi::PyType_Slot where - T: for<'p> PyNumberIMatmulProtocol<'p>, + Self: for<'p> PyNumberIMatmulProtocol<'p>, { - self.nb_inplace_matrix_multiply = - py_binary_self_func!(PyNumberIMatmulProtocol, T::__imatmul__); - } - pub(crate) fn update_slots(&self, slots: &mut crate::pyclass::TypeSlots) { - slots.maybe_push(ffi::Py_nb_add, self.nb_add.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_subtract, self.nb_subtract.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_multiply, self.nb_multiply.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_remainder, self.nb_remainder.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_divmod, self.nb_divmod.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_power, self.nb_power.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_negative, self.nb_negative.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_positive, self.nb_positive.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_absolute, self.nb_absolute.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_bool, self.nb_bool.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_invert, self.nb_invert.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_lshift, self.nb_lshift.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_rshift, self.nb_rshift.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_and, self.nb_and.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_xor, self.nb_xor.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_or, self.nb_or.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_int, self.nb_int.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_float, self.nb_float.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_inplace_add, self.nb_inplace_add.map(|v| v as _)); - slots.maybe_push( - ffi::Py_nb_inplace_subtract, - self.nb_inplace_subtract.map(|v| v as _), - ); - slots.maybe_push( - ffi::Py_nb_inplace_multiply, - self.nb_inplace_multiply.map(|v| v as _), - ); - slots.maybe_push( - ffi::Py_nb_inplace_remainder, - self.nb_inplace_remainder.map(|v| v as _), - ); - slots.maybe_push( - ffi::Py_nb_inplace_power, - self.nb_inplace_power.map(|v| v as _), - ); - slots.maybe_push( - ffi::Py_nb_inplace_lshift, - self.nb_inplace_lshift.map(|v| v as _), - ); - slots.maybe_push( - ffi::Py_nb_inplace_rshift, - self.nb_inplace_rshift.map(|v| v as _), - ); - slots.maybe_push(ffi::Py_nb_inplace_and, self.nb_inplace_and.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_inplace_xor, self.nb_inplace_xor.map(|v| v as _)); - slots.maybe_push(ffi::Py_nb_inplace_or, self.nb_inplace_or.map(|v| v as _)); - slots.maybe_push( - ffi::Py_nb_floor_divide, - self.nb_floor_divide.map(|v| v as _), - ); - slots.maybe_push(ffi::Py_nb_true_divide, self.nb_true_divide.map(|v| v as _)); - slots.maybe_push( - ffi::Py_nb_inplace_floor_divide, - self.nb_inplace_floor_divide.map(|v| v as _), - ); - slots.maybe_push( - ffi::Py_nb_inplace_true_divide, - self.nb_inplace_true_divide.map(|v| v as _), - ); - slots.maybe_push(ffi::Py_nb_index, self.nb_index.map(|v| v as _)); - slots.maybe_push( - ffi::Py_nb_matrix_multiply, - self.nb_matrix_multiply.map(|v| v as _), - ); - slots.maybe_push( - ffi::Py_nb_inplace_matrix_multiply, - self.nb_inplace_matrix_multiply.map(|v| v as _), - ); + ffi::PyType_Slot { + slot: ffi::Py_nb_inplace_matrix_multiply, + pfunc: py_binary_self_func!(PyNumberIMatmulProtocol, Self::__imatmul__) as _, + } } } + +impl<'p, T> PyNumberSlots for T where T: PyNumberProtocol<'p> {} diff --git a/src/class/proto_methods.rs b/src/class/proto_methods.rs index e9018789cfa..6093018b74f 100644 --- a/src/class/proto_methods.rs +++ b/src/class/proto_methods.rs @@ -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> { - None - } - fn basic_methods() -> Option> { - None - } - #[cfg(not(Py_LIMITED_API))] - fn buffer_methods() -> Option> { - None - } - fn descr_methods() -> Option> { - None - } - fn gc_methods() -> Option> { - None + fn get_type_slots() -> Vec { + vec![] } - fn mapping_methods() -> Option> { - None - } - fn number_methods() -> Option> { - None - } - fn iter_methods() -> Option> { - None - } - fn sequence_methods() -> Option> { + fn get_buffer() -> Option { 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), + Buffer(PyBufferProcs), } -impl PyProtoMethods for T { - fn async_methods() -> Option> { - NonNull::new(Self::registry().async_methods.load(Ordering::Relaxed)) - } - fn basic_methods() -> Option> { - NonNull::new(Self::registry().basic_methods.load(Ordering::Relaxed)) - } - #[cfg(not(Py_LIMITED_API))] - fn buffer_methods() -> Option> { - NonNull::new(Self::registry().buffer_methods.load(Ordering::Relaxed)) - } - fn descr_methods() -> Option> { - NonNull::new(Self::registry().descr_methods.load(Ordering::Relaxed)) - } - fn gc_methods() -> Option> { - NonNull::new(Self::registry().gc_methods.load(Ordering::Relaxed)) - } - fn mapping_methods() -> Option> { - NonNull::new(Self::registry().mapping_methods.load(Ordering::Relaxed)) - } - fn number_methods() -> Option> { - NonNull::new(Self::registry().number_methods.load(Ordering::Relaxed)) - } - fn iter_methods() -> Option> { - NonNull::new(Self::registry().iter_methods.load(Ordering::Relaxed)) - } - fn sequence_methods() -> Option> { - NonNull::new(Self::registry().sequence_methods.load(Ordering::Relaxed)) - } +#[doc(hidden)] +#[cfg(feature = "macros")] +pub trait PyProtoMethodsInventory: inventory::Collect { + fn new(methods: PyProtoMethodDef) -> Self; + fn get(&'static self) -> &'static PyProtoMethodDef; } -/// Stores all method protocols. -/// Used in the proc-macro code as a static variable. #[doc(hidden)] -pub struct PyProtoRegistry { - /// Async protocols. - async_methods: AtomicPtr, - /// Basic protocols. - basic_methods: AtomicPtr, - /// Buffer protocols. - #[cfg(not(Py_LIMITED_API))] - buffer_methods: AtomicPtr, - /// Descr pProtocols. - descr_methods: AtomicPtr, - /// GC protocols. - gc_methods: AtomicPtr, - /// Mapping protocols. - mapping_methods: AtomicPtr, - /// Number protocols. - number_methods: AtomicPtr, - /// Iterator protocols. - iter_methods: AtomicPtr, - /// Sequence protocols. - sequence_methods: AtomicPtr, +#[cfg(feature = "macros")] +pub trait HasProtoMethodsInventory { + type ProtoMethods: PyProtoMethodsInventory; } -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()), - } - } - pub fn set_async_methods(&self, methods: PyAsyncMethods) { - self.async_methods - .store(Box::into_raw(Box::new(methods)), Ordering::Relaxed) +#[cfg(feature = "macros")] +impl PyProtoMethods for T { + fn get_type_slots() -> Vec { + inventory::iter:: + .into_iter() + .filter_map(|def| match def.get() { + PyProtoMethodDef::Slots(slots) => Some(slots), + PyProtoMethodDef::Buffer(_) => None, + }) + .flatten() + .cloned() + .collect() } - 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 { + inventory::iter:: + .into_iter() + .find_map(|def| match def.get() { + PyProtoMethodDef::Slots(_) => None, + PyProtoMethodDef::Buffer(buf) => Some(buf.clone()), + }) } } diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index 4f6998b1267..78cc552e322 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -96,34 +96,43 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> { type Result: IntoPyCallbackOutput; } +/// Extension trait for proc-macro backend. #[doc(hidden)] -impl PyAsyncMethods { - pub fn set_await(&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__); + ffi::PyType_Slot { + slot: ffi::Py_am_await, + pfunc: py_unarys_func!(PyAsyncAwaitProtocol, Self::__await__) as _, + } } - pub fn set_aiter(&mut self) + + fn get_aiter() -> ffi::PyType_Slot where - T: for<'p> PyAsyncAiterProtocol<'p>, + Self: for<'p> PyAsyncAiterProtocol<'p>, { - self.am_aiter = py_unarys_func!(PyAsyncAiterProtocol, T::__aiter__); + ffi::PyType_Slot { + slot: ffi::Py_am_await, + pfunc: py_unarys_func!(PyAsyncAiterProtocol, Self::__aiter__) as _, + } } - pub fn set_anext(&mut self) + + fn get_anext() -> ffi::PyType_Slot where - T: for<'p> PyAsyncAnextProtocol<'p>, + Self: for<'p> PyAsyncAnextProtocol<'p>, { - self.am_anext = am_anext::(); - } - - 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 _)); + 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 { Yield(T), Return(U), @@ -166,11 +175,3 @@ where } } } - -#[inline] -fn am_anext() -> Option -where - T: for<'p> PyAsyncAnextProtocol<'p>, -{ - py_unarys_func!(PyAsyncAnextProtocol, T::__anext__) -} diff --git a/src/class/sequence.rs b/src/class/sequence.rs index bc9f2da4937..ccbc35ace88 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -167,103 +167,119 @@ pub trait PySequenceInplaceRepeatProtocol<'p>: type Result: IntoPyCallbackOutput; } +/// Extension trait for proc-macro backend. #[doc(hidden)] -impl PySequenceMethods { - pub fn set_len(&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(&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(&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(&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(&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::(); + ffi::PyType_Slot { + slot: ffi::Py_sq_length, + pfunc: sq_ass_item_impl::set_item::() as _, + } } - pub fn set_delitem(&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::(); + ffi::PyType_Slot { + slot: ffi::Py_sq_length, + pfunc: sq_ass_item_impl::del_item::() as _, + } } - pub fn set_setdelitem(&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::(); + ffi::PyType_Slot { + slot: ffi::Py_sq_length, + pfunc: sq_ass_item_impl::set_del_item::() as _, + } } - pub fn set_contains(&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(&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(&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() -> Option + pub(super) fn set_item() -> 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::) + wrap:: } - pub(super) fn del_item() -> Option + pub(super) fn del_item() -> ffi::ssizeobjargproc where T: for<'p> PySequenceDelItemProtocol<'p>, { @@ -319,10 +335,10 @@ mod sq_ass_item_impl { } }) } - Some(wrap::) + wrap:: } - pub(super) fn set_del_item() -> Option + pub(super) fn set_del_item() -> ffi::ssizeobjargproc where T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>, { @@ -347,6 +363,6 @@ mod sq_ass_item_impl { } }) } - Some(wrap::) + wrap:: } } diff --git a/src/pyclass.rs b/src/pyclass.rs index c13f717592a..739e1528d13 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -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::(); 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::(module_name)?, basicsize: std::mem::size_of::() as c_int, itemsize: 0, - flags: py_class_flags::(), + flags: py_class_flags::(has_gc_methods), slots: slots.0.as_mut_slice().as_mut_ptr(), }; @@ -274,10 +250,10 @@ fn tp_init_additional(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(type_object: *mut ffi::PyTypeObject) { #[cfg(Py_LIMITED_API)] fn tp_init_additional(_type_object: *mut ffi::PyTypeObject) {} -fn py_class_flags() -> c_uint { - let mut flags = if T::gc_methods().is_some() || T::FLAGS & type_flags::GC != 0 { +fn py_class_flags(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 From 6627658127cfe529f83c4c7c4bd6d1b8fcbd4527 Mon Sep 17 00:00:00 2001 From: kngwyu Date: Tue, 20 Oct 2020 00:24:45 +0900 Subject: [PATCH 2/3] Renew proc-macros for new `#[pyproto]` backend --- guide/src/class.md | 20 ++- pyo3-derive-backend/src/defs.rs | 270 ++++++++++++++--------------- pyo3-derive-backend/src/pyclass.rs | 33 +++- pyo3-derive-backend/src/pyproto.rs | 70 ++++---- src/class/basic.rs | 2 +- src/class/buffer.rs | 85 ++++----- src/class/descr.rs | 3 +- src/class/number.rs | 8 +- src/class/proto_methods.rs | 29 +++- src/class/pyasync.rs | 13 +- src/class/sequence.rs | 57 +----- 11 files changed, 279 insertions(+), 311 deletions(-) diff --git a/guide/src/class.md b/guide/src/class.md index ecdcc76f919..bd3ad360b78 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -772,13 +772,23 @@ impl pyo3::class::methods::HasMethodsInventory for MyClass { } pyo3::inventory::collect!(Pyo3MethodsInventoryForMyClass); -impl pyo3::class::proto_methods::HasProtoRegistry for MyClass { - fn registry() -> &'static pyo3::class::proto_methods::PyProtoRegistry { - static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry - = pyo3::class::proto_methods::PyProtoRegistry::new(); - ®ISTRY + +pub struct Pyo3ProtoInventoryForMyClass { + def: pyo3::class::proto_methods::PyProtoMethodDef, +} +impl pyo3::class::proto_methods::PyProtoInventory for Pyo3ProtoInventoryForMyClass { + fn new(def: pyo3::class::proto_methods::PyProtoMethodDef) -> Self { + Self { def } + } + fn get(&'static self) -> &'static pyo3::class::proto_methods::PyProtoMethodDef { + &self.def } } +impl pyo3::class::proto_methods::HasProtoInventory for MyClass { + type ProtoMethods = Pyo3ProtoInventoryForMyClass; +} +pyo3::inventory::collect!(Pyo3ProtoInventoryForMyClass); + impl pyo3::pyclass::PyClassSend for MyClass { type ThreadChecker = pyo3::pyclass::ThreadCheckerStub; diff --git a/pyo3-derive-backend/src/defs.rs b/pyo3-derive-backend/src/defs.rs index 6199a722b8c..6a1d628c8b6 100644 --- a/pyo3-derive-backend/src/defs.rs +++ b/pyo3-derive-backend/src/defs.rs @@ -6,16 +6,14 @@ use std::collections::HashSet; pub struct Proto { /// The name of this protocol. E.g., Iter. pub name: &'static str, - /// The name of slot table. E.g., PyIterMethods. - pub slot_table: &'static str, - /// The name of the setter used to set the table to `PyProtoRegistry`. - pub set_slot_table: &'static str, + /// Extension trait that has `get_*` methods + pub extension_trait: &'static str, /// All methods. pub methods: &'static [MethodProto], /// All methods registered as normal methods like `#[pymethods]`. pub py_methods: &'static [PyMethod], /// All methods registered to the slot table. - slot_setters: &'static [SlotSetter], + slot_getters: &'static [SlotGetter], } impl Proto { @@ -32,13 +30,13 @@ impl Proto { self.py_methods.iter().find(|m| query == m.name) } // Since the order matters, we expose only the iterator instead of the slice. - pub(crate) fn setters( + pub(crate) fn slot_getters( &self, mut implemented_protocols: HashSet, ) -> impl Iterator { - self.slot_setters.iter().filter_map(move |setter| { + self.slot_getters.iter().filter_map(move |getter| { // If any required method is not implemented, we skip this setter. - if setter + if getter .proto_names .iter() .any(|name| !implemented_protocols.contains(*name)) @@ -47,10 +45,10 @@ impl Proto { } // To use 'paired' setter in priority, we remove used protocols. // For example, if set_add_radd is already used, we shouldn't use set_add and set_radd. - for name in setter.proto_names { + for name in getter.proto_names { implemented_protocols.remove(*name); } - Some(setter.set_function) + Some(getter.get_function) }) } } @@ -82,27 +80,26 @@ impl PyMethod { } /// Represents a setter used to register a method to the method table. -struct SlotSetter { +struct SlotGetter { /// Protocols necessary for invoking this setter. /// E.g., we need `__setattr__` and `__delattr__` for invoking `set_setdelitem`. pub proto_names: &'static [&'static str], /// The name of the setter called to the method table. - pub set_function: &'static str, + pub get_function: &'static str, } -impl SlotSetter { - const fn new(names: &'static [&'static str], set_function: &'static str) -> Self { - SlotSetter { +impl SlotGetter { + const fn new(names: &'static [&'static str], get_function: &'static str) -> Self { + SlotGetter { proto_names: names, - set_function, + get_function, } } } pub const OBJECT: Proto = Proto { name: "Object", - slot_table: "pyo3::class::basic::PyObjectMethods", - set_slot_table: "set_basic_methods", + extension_trait: "pyo3::class::basic::PyBasicSlots", methods: &[ MethodProto::Binary { name: "__getattr__", @@ -156,23 +153,22 @@ pub const OBJECT: Proto = Proto { PyMethod::new("__bytes__", "pyo3::class::basic::BytesProtocolImpl"), PyMethod::new("__unicode__", "pyo3::class::basic::UnicodeProtocolImpl"), ], - slot_setters: &[ - SlotSetter::new(&["__str__"], "set_str"), - SlotSetter::new(&["__repr__"], "set_repr"), - SlotSetter::new(&["__hash__"], "set_hash"), - SlotSetter::new(&["__getattr__"], "set_getattr"), - SlotSetter::new(&["__richcmp__"], "set_richcompare"), - SlotSetter::new(&["__setattr__", "__delattr__"], "set_setdelattr"), - SlotSetter::new(&["__setattr__"], "set_setattr"), - SlotSetter::new(&["__delattr__"], "set_delattr"), - SlotSetter::new(&["__bool__"], "set_bool"), + slot_getters: &[ + SlotGetter::new(&["__str__"], "get_str"), + SlotGetter::new(&["__repr__"], "get_repr"), + SlotGetter::new(&["__hash__"], "get_hash"), + SlotGetter::new(&["__getattr__"], "get_getattr"), + SlotGetter::new(&["__richcmp__"], "get_richcompare"), + SlotGetter::new(&["__setattr__", "__delattr__"], "get_setdelattr"), + SlotGetter::new(&["__setattr__"], "get_setattr"), + SlotGetter::new(&["__delattr__"], "get_delattr"), + SlotGetter::new(&["__bool__"], "get_bool"), ], }; pub const ASYNC: Proto = Proto { name: "Async", - slot_table: "pyo3::class::pyasync::PyAsyncMethods", - set_slot_table: "set_async_methods", + extension_trait: "pyo3::class::pyasync::PyAsyncSlots", methods: &[ MethodProto::UnaryS { name: "__await__", @@ -211,17 +207,16 @@ pub const ASYNC: Proto = Proto { "pyo3::class::pyasync::PyAsyncAexitProtocolImpl", ), ], - slot_setters: &[ - SlotSetter::new(&["__await__"], "set_await"), - SlotSetter::new(&["__aiter__"], "set_aiter"), - SlotSetter::new(&["__anext__"], "set_anext"), + slot_getters: &[ + SlotGetter::new(&["__await__"], "get_await"), + SlotGetter::new(&["__aiter__"], "get_aiter"), + SlotGetter::new(&["__anext__"], "get_anext"), ], }; pub const BUFFER: Proto = Proto { name: "Buffer", - slot_table: "pyo3::class::buffer::PyBufferProcs", - set_slot_table: "set_buffer_methods", + extension_trait: "pyo3::class::buffer::PyBufferSlots", methods: &[ MethodProto::Unary { name: "bf_getbuffer", @@ -233,16 +228,15 @@ pub const BUFFER: Proto = Proto { }, ], py_methods: &[], - slot_setters: &[ - SlotSetter::new(&["bf_getbuffer"], "set_getbuffer"), - SlotSetter::new(&["bf_releasebuffer"], "set_releasebuffer"), + slot_getters: &[ + SlotGetter::new(&["bf_getbuffer"], "get_getbuffer"), + SlotGetter::new(&["bf_releasebuffer"], "get_releasebuffer"), ], }; pub const CONTEXT: Proto = Proto { name: "Context", - slot_table: "", - set_slot_table: "", + extension_trait: "", methods: &[ MethodProto::Unary { name: "__enter__", @@ -266,13 +260,12 @@ pub const CONTEXT: Proto = Proto { "pyo3::class::context::PyContextExitProtocolImpl", ), ], - slot_setters: &[], + slot_getters: &[], }; pub const GC: Proto = Proto { name: "GC", - slot_table: "pyo3::class::gc::PyGCMethods", - set_slot_table: "set_gc_methods", + extension_trait: "pyo3::class::gc::PyGCSlots", methods: &[ MethodProto::Free { name: "__traverse__", @@ -284,16 +277,15 @@ pub const GC: Proto = Proto { }, ], py_methods: &[], - slot_setters: &[ - SlotSetter::new(&["__traverse__"], "set_traverse"), - SlotSetter::new(&["__clear__"], "set_clear"), + slot_getters: &[ + SlotGetter::new(&["__traverse__"], "get_traverse"), + SlotGetter::new(&["__clear__"], "get_clear"), ], }; pub const DESCR: Proto = Proto { name: "Descriptor", - slot_table: "pyo3::class::descr::PyDescrMethods", - set_slot_table: "set_descr_methods", + extension_trait: "pyo3::class::descr::PyDescrSlots", methods: &[ MethodProto::TernaryS { name: "__get__", @@ -327,16 +319,15 @@ pub const DESCR: Proto = Proto { "pyo3::class::context::PyDescrNameProtocolImpl", ), ], - slot_setters: &[ - SlotSetter::new(&["__get__"], "set_descr_get"), - SlotSetter::new(&["__set__"], "set_descr_set"), + slot_getters: &[ + SlotGetter::new(&["__get__"], "get_descr_get"), + SlotGetter::new(&["__set__"], "get_descr_set"), ], }; pub const ITER: Proto = Proto { name: "Iter", - slot_table: "pyo3::class::iter::PyIterMethods", - set_slot_table: "set_iter_methods", + extension_trait: "pyo3::class::iter::PyIterSlots", py_methods: &[], methods: &[ MethodProto::UnaryS { @@ -350,16 +341,15 @@ pub const ITER: Proto = Proto { proto: "pyo3::class::iter::PyIterNextProtocol", }, ], - slot_setters: &[ - SlotSetter::new(&["__iter__"], "set_iter"), - SlotSetter::new(&["__next__"], "set_iternext"), + slot_getters: &[ + SlotGetter::new(&["__iter__"], "get_iter"), + SlotGetter::new(&["__next__"], "get_iternext"), ], }; pub const MAPPING: Proto = Proto { name: "Mapping", - slot_table: "pyo3::class::mapping::PyMappingMethods", - set_slot_table: "set_mapping_methods", + extension_trait: "pyo3::class::mapping::PyMappingSlots", methods: &[ MethodProto::Unary { name: "__len__", @@ -390,19 +380,18 @@ pub const MAPPING: Proto = Proto { "__reversed__", "pyo3::class::mapping::PyMappingReversedProtocolImpl", )], - slot_setters: &[ - SlotSetter::new(&["__len__"], "set_length"), - SlotSetter::new(&["__getitem__"], "set_getitem"), - SlotSetter::new(&["__setitem__", "__delitem__"], "set_setdelitem"), - SlotSetter::new(&["__setitem__"], "set_setitem"), - SlotSetter::new(&["__delitem__"], "set_delitem"), + slot_getters: &[ + SlotGetter::new(&["__len__"], "get_length"), + SlotGetter::new(&["__getitem__"], "get_getitem"), + SlotGetter::new(&["__setitem__", "__delitem__"], "get_setdelitem"), + SlotGetter::new(&["__setitem__"], "get_setitem"), + SlotGetter::new(&["__delitem__"], "get_delitem"), ], }; pub const SEQ: Proto = Proto { name: "Sequence", - slot_table: "pyo3::class::sequence::PySequenceMethods", - set_slot_table: "set_sequence_methods", + extension_trait: "pyo3::class::sequence::PySequenceSlots", methods: &[ MethodProto::Unary { name: "__len__", @@ -451,24 +440,23 @@ pub const SEQ: Proto = Proto { }, ], py_methods: &[], - slot_setters: &[ - SlotSetter::new(&["__len__"], "set_len"), - SlotSetter::new(&["__concat__"], "set_concat"), - SlotSetter::new(&["__repeat__"], "set_repeat"), - SlotSetter::new(&["__getitem__"], "set_getitem"), - SlotSetter::new(&["__setitem__", "__delitem__"], "set_setdelitem"), - SlotSetter::new(&["__setitem__"], "set_setitem"), - SlotSetter::new(&["__delitem__"], "set_delitem"), - SlotSetter::new(&["__contains__"], "set_contains"), - SlotSetter::new(&["__inplace_concat__"], "set_inplace_concat"), - SlotSetter::new(&["__inplace_repeat__"], "set_inplace_repeat"), + slot_getters: &[ + SlotGetter::new(&["__len__"], "get_len"), + SlotGetter::new(&["__concat__"], "get_concat"), + SlotGetter::new(&["__repeat__"], "get_repeat"), + SlotGetter::new(&["__getitem__"], "get_getitem"), + SlotGetter::new(&["__setitem__", "__delitem__"], "get_setdelitem"), + SlotGetter::new(&["__setitem__"], "get_setitem"), + SlotGetter::new(&["__delitem__"], "get_delitem"), + SlotGetter::new(&["__contains__"], "get_contains"), + SlotGetter::new(&["__inplace_concat__"], "get_inplace_concat"), + SlotGetter::new(&["__inplace_repeat__"], "get_inplace_repeat"), ], }; pub const NUM: Proto = Proto { name: "Number", - slot_table: "pyo3::class::number::PyNumberMethods", - set_slot_table: "set_number_methods", + extension_trait: "pyo3::class::number::PyNumberSlots", methods: &[ MethodProto::BinaryS { name: "__add__", @@ -771,66 +759,66 @@ pub const NUM: Proto = Proto { "pyo3::class::number::PyNumberRoundProtocolImpl", ), ], - slot_setters: &[ - SlotSetter::new(&["__add__", "__radd__"], "set_add_radd"), - SlotSetter::new(&["__add__"], "set_add"), - SlotSetter::new(&["__radd__"], "set_radd"), - SlotSetter::new(&["__sub__", "__rsub__"], "set_sub_rsub"), - SlotSetter::new(&["__sub__"], "set_sub"), - SlotSetter::new(&["__rsub__"], "set_rsub"), - SlotSetter::new(&["__mul__", "__rmul__"], "set_mul_rmul"), - SlotSetter::new(&["__mul__"], "set_mul"), - SlotSetter::new(&["__rmul__"], "set_rmul"), - SlotSetter::new(&["__mod__"], "set_mod"), - SlotSetter::new(&["__divmod__", "__rdivmod__"], "set_divmod_rdivmod"), - SlotSetter::new(&["__divmod__"], "set_divmod"), - SlotSetter::new(&["__rdivmod__"], "set_rdivmod"), - SlotSetter::new(&["__pow__", "__rpow__"], "set_pow_rpow"), - SlotSetter::new(&["__pow__"], "set_pow"), - SlotSetter::new(&["__rpow__"], "set_rpow"), - SlotSetter::new(&["__neg__"], "set_neg"), - SlotSetter::new(&["__pos__"], "set_pos"), - SlotSetter::new(&["__abs__"], "set_abs"), - SlotSetter::new(&["__invert__"], "set_invert"), - SlotSetter::new(&["__lshift__", "__rlshift__"], "set_lshift_rlshift"), - SlotSetter::new(&["__lshift__"], "set_lshift"), - SlotSetter::new(&["__rlshift__"], "set_rlshift"), - SlotSetter::new(&["__rshift__", "__rrshift__"], "set_rshift_rrshift"), - SlotSetter::new(&["__rshift__"], "set_rshift"), - SlotSetter::new(&["__rrshift__"], "set_rrshift"), - SlotSetter::new(&["__and__", "__rand__"], "set_and_rand"), - SlotSetter::new(&["__and__"], "set_and"), - SlotSetter::new(&["__rand__"], "set_rand"), - SlotSetter::new(&["__xor__", "__rxor__"], "set_xor_rxor"), - SlotSetter::new(&["__xor__"], "set_xor"), - SlotSetter::new(&["__rxor__"], "set_rxor"), - SlotSetter::new(&["__or__", "__ror__"], "set_or_ror"), - SlotSetter::new(&["__or__"], "set_or"), - SlotSetter::new(&["__ror__"], "set_ror"), - SlotSetter::new(&["__int__"], "set_int"), - SlotSetter::new(&["__float__"], "set_float"), - SlotSetter::new(&["__iadd__"], "set_iadd"), - SlotSetter::new(&["__isub__"], "set_isub"), - SlotSetter::new(&["__imul__"], "set_imul"), - SlotSetter::new(&["__imod__"], "set_imod"), - SlotSetter::new(&["__ipow__"], "set_ipow"), - SlotSetter::new(&["__ilshift__"], "set_ilshift"), - SlotSetter::new(&["__irshift__"], "set_irshift"), - SlotSetter::new(&["__iand__"], "set_iand"), - SlotSetter::new(&["__ixor__"], "set_ixor"), - SlotSetter::new(&["__ior__"], "set_ior"), - SlotSetter::new(&["__floordiv__", "__rfloordiv__"], "set_floordiv_rfloordiv"), - SlotSetter::new(&["__floordiv__"], "set_floordiv"), - SlotSetter::new(&["__rfloordiv__"], "set_rfloordiv"), - SlotSetter::new(&["__truediv__", "__rtruediv__"], "set_truediv_rtruediv"), - SlotSetter::new(&["__truediv__"], "set_truediv"), - SlotSetter::new(&["__rtruediv__"], "set_rtruediv"), - SlotSetter::new(&["__ifloordiv__"], "set_ifloordiv"), - SlotSetter::new(&["__itruediv__"], "set_itruediv"), - SlotSetter::new(&["__index__"], "set_index"), - SlotSetter::new(&["__matmul__", "__rmatmul__"], "set_matmul_rmatmul"), - SlotSetter::new(&["__matmul__"], "set_matmul"), - SlotSetter::new(&["__rmatmul__"], "set_rmatmul"), - SlotSetter::new(&["__imatmul__"], "set_imatmul"), + slot_getters: &[ + SlotGetter::new(&["__add__", "__radd__"], "get_add_radd"), + SlotGetter::new(&["__add__"], "get_add"), + SlotGetter::new(&["__radd__"], "get_radd"), + SlotGetter::new(&["__sub__", "__rsub__"], "get_sub_rsub"), + SlotGetter::new(&["__sub__"], "get_sub"), + SlotGetter::new(&["__rsub__"], "get_rsub"), + SlotGetter::new(&["__mul__", "__rmul__"], "get_mul_rmul"), + SlotGetter::new(&["__mul__"], "get_mul"), + SlotGetter::new(&["__rmul__"], "get_rmul"), + SlotGetter::new(&["__mod__"], "get_mod"), + SlotGetter::new(&["__divmod__", "__rdivmod__"], "get_divmod_rdivmod"), + SlotGetter::new(&["__divmod__"], "get_divmod"), + SlotGetter::new(&["__rdivmod__"], "get_rdivmod"), + SlotGetter::new(&["__pow__", "__rpow__"], "get_pow_rpow"), + SlotGetter::new(&["__pow__"], "get_pow"), + SlotGetter::new(&["__rpow__"], "get_rpow"), + SlotGetter::new(&["__neg__"], "get_neg"), + SlotGetter::new(&["__pos__"], "get_pos"), + SlotGetter::new(&["__abs__"], "get_abs"), + SlotGetter::new(&["__invert__"], "get_invert"), + SlotGetter::new(&["__lshift__", "__rlshift__"], "get_lshift_rlshift"), + SlotGetter::new(&["__lshift__"], "get_lshift"), + SlotGetter::new(&["__rlshift__"], "get_rlshift"), + SlotGetter::new(&["__rshift__", "__rrshift__"], "get_rshift_rrshift"), + SlotGetter::new(&["__rshift__"], "get_rshift"), + SlotGetter::new(&["__rrshift__"], "get_rrshift"), + SlotGetter::new(&["__and__", "__rand__"], "get_and_rand"), + SlotGetter::new(&["__and__"], "get_and"), + SlotGetter::new(&["__rand__"], "get_rand"), + SlotGetter::new(&["__xor__", "__rxor__"], "get_xor_rxor"), + SlotGetter::new(&["__xor__"], "get_xor"), + SlotGetter::new(&["__rxor__"], "get_rxor"), + SlotGetter::new(&["__or__", "__ror__"], "get_or_ror"), + SlotGetter::new(&["__or__"], "get_or"), + SlotGetter::new(&["__ror__"], "get_ror"), + SlotGetter::new(&["__int__"], "get_int"), + SlotGetter::new(&["__float__"], "get_float"), + SlotGetter::new(&["__iadd__"], "get_iadd"), + SlotGetter::new(&["__isub__"], "get_isub"), + SlotGetter::new(&["__imul__"], "get_imul"), + SlotGetter::new(&["__imod__"], "get_imod"), + SlotGetter::new(&["__ipow__"], "get_ipow"), + SlotGetter::new(&["__ilshift__"], "get_ilshift"), + SlotGetter::new(&["__irshift__"], "get_irshift"), + SlotGetter::new(&["__iand__"], "get_iand"), + SlotGetter::new(&["__ixor__"], "get_ixor"), + SlotGetter::new(&["__ior__"], "get_ior"), + SlotGetter::new(&["__floordiv__", "__rfloordiv__"], "get_floordiv_rfloordiv"), + SlotGetter::new(&["__floordiv__"], "get_floordiv"), + SlotGetter::new(&["__rfloordiv__"], "get_rfloordiv"), + SlotGetter::new(&["__truediv__", "__rtruediv__"], "get_truediv_rtruediv"), + SlotGetter::new(&["__truediv__"], "get_truediv"), + SlotGetter::new(&["__rtruediv__"], "get_rtruediv"), + SlotGetter::new(&["__ifloordiv__"], "get_ifloordiv"), + SlotGetter::new(&["__itruediv__"], "get_itruediv"), + SlotGetter::new(&["__index__"], "get_index"), + SlotGetter::new(&["__matmul__", "__rmatmul__"], "get_matmul_rmatmul"), + SlotGetter::new(&["__matmul__"], "get_matmul"), + SlotGetter::new(&["__rmatmul__"], "get_rmatmul"), + SlotGetter::new(&["__imatmul__"], "get_imatmul"), ], }; diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index 032935d5776..aca7e7d46c7 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -234,16 +234,31 @@ fn impl_methods_inventory(cls: &syn::Ident) -> TokenStream { } } -/// Implement `HasProtoRegistry` for the class for lazy protocol initialization. -fn impl_proto_registry(cls: &syn::Ident) -> TokenStream { +/// Implement `HasProtoInventory` for the class for lazy protocol initialization. +fn impl_proto_inventory(cls: &syn::Ident) -> TokenStream { + // Try to build a unique type for better error messages + let name = format!("Pyo3ProtoInventoryFor{}", cls); + let inventory_cls = syn::Ident::new(&name, Span::call_site()); + quote! { - impl pyo3::class::proto_methods::HasProtoRegistry for #cls { - fn registry() -> &'static pyo3::class::proto_methods::PyProtoRegistry { - static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry - = pyo3::class::proto_methods::PyProtoRegistry::new(); - ®ISTRY + #[doc(hidden)] + pub struct #inventory_cls { + def: pyo3::class::proto_methods::PyProtoMethodDef, + } + impl pyo3::class::proto_methods::PyProtoInventory for #inventory_cls { + fn new(def: pyo3::class::proto_methods::PyProtoMethodDef) -> Self { + Self { def } } + fn get(&'static self) -> &'static pyo3::class::proto_methods::PyProtoMethodDef { + &self.def + } + } + + impl pyo3::class::proto_methods::HasProtoInventory for #cls { + type ProtoMethods = #inventory_cls; } + + pyo3::inventory::collect!(#inventory_cls); } } @@ -351,7 +366,7 @@ fn impl_class( }; let impl_inventory = impl_methods_inventory(&cls); - let impl_proto_registry = impl_proto_registry(&cls); + let impl_proto_inventory = impl_proto_inventory(&cls); let base = &attr.base; let flags = &attr.flags; @@ -440,7 +455,7 @@ fn impl_class( #impl_inventory - #impl_proto_registry + #impl_proto_inventory #extra diff --git a/pyo3-derive-backend/src/pyproto.rs b/pyo3-derive-backend/src/pyproto.rs index 7c6cbf1a7ae..fe60e7a14fa 100644 --- a/pyo3-derive-backend/src/pyproto.rs +++ b/pyo3-derive-backend/src/pyproto.rs @@ -106,16 +106,16 @@ fn impl_proto_impl( } } } - let inventory_submission = inventory_submission(py_methods, ty); - let slot_initialization = slot_initialization(method_names, ty, proto)?; + let normal_methods = submit_normal_methods(py_methods, ty); + let protocol_methods = submit_protocol_methods(method_names, ty, proto)?; Ok(quote! { #trait_impls - #inventory_submission - #slot_initialization + #normal_methods + #protocol_methods }) } -fn inventory_submission(py_methods: Vec, ty: &syn::Type) -> TokenStream { +fn submit_normal_methods(py_methods: Vec, ty: &syn::Type) -> TokenStream { if py_methods.is_empty() { return quote! {}; } @@ -129,42 +129,46 @@ fn inventory_submission(py_methods: Vec, ty: &syn::Type) -> TokenSt } } -fn slot_initialization( +fn submit_protocol_methods( method_names: HashSet, ty: &syn::Type, proto: &defs::Proto, ) -> syn::Result { - // Collect initializers - let mut initializers: Vec = vec![]; - for setter in proto.setters(method_names) { - // Add slot methods to PyProtoRegistry - let set = syn::Ident::new(setter, Span::call_site()); - initializers.push(quote! { table.#set::<#ty>(); }); + if proto.extension_trait == "" { + return Ok(quote! {}); + } + let ext_trait: syn::Path = syn::parse_str(proto.extension_trait)?; + let mut tokens: Vec = vec![]; + if proto.name == "Buffer" { + // For buffer, we construct `PyProtoMethods` from PyBufferProcs + tokens.push(quote! { + let mut proto_methods = pyo3::ffi::PyBufferProcs::default(); + }); + for getter in proto.slot_getters(method_names) { + let get = syn::Ident::new(getter, Span::call_site()); + let field = syn::Ident::new(&format!("bf_{}", &getter[4..]), Span::call_site()); + tokens.push(quote! { proto_methods.#field = Some(<#ty as #ext_trait>::#get()); }); + } + } else { + // For other protocols, we construct `PyProtoMethods` from Vec + tokens.push(quote! { let mut proto_methods = vec![]; }); + for getter in proto.slot_getters(method_names) { + let get = syn::Ident::new(getter, Span::call_site()); + tokens.push(quote! { proto_methods.push(<#ty as #ext_trait>::#get()); }); + } } - if initializers.is_empty() { + if tokens.len() <= 1 { return Ok(quote! {}); } - let table: syn::Path = syn::parse_str(proto.slot_table)?; - let set = syn::Ident::new(proto.set_slot_table, Span::call_site()); - let ty_hash = typename_hash(ty); - let init = syn::Ident::new( - &format!("__init_{}_{}", proto.name, ty_hash), - Span::call_site(), - ); Ok(quote! { - #[allow(non_snake_case)] - #[pyo3::ctor::ctor] - fn #init() { - let mut table = #table::default(); - #(#initializers)* - <#ty as pyo3::class::proto_methods::HasProtoRegistry>::registry().#set(table); + pyo3::inventory::submit! { + #![crate = pyo3] { + type Inventory = + <#ty as pyo3::class::proto_methods::HasProtoInventory>::ProtoMethods; + ::new( + { #(#tokens)* proto_methods.into() } + ) + } } }) } - -fn typename_hash(ty: &syn::Type) -> u64 { - use std::hash::{Hash, Hasher}; - let mut hasher = std::collections::hash_map::DefaultHasher::new(); - ty.hash(&mut hasher); - hasher.finish() -} diff --git a/src/class/basic.rs b/src/class/basic.rs index 9223b8e7f80..24ff4135eb6 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -181,7 +181,7 @@ pub trait PyBasicSlots { Self: for<'p> PyObjectRichcmpProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_tp_getattro, + slot: ffi::Py_tp_richcompare, pfunc: tp_richcompare::() as _, } } diff --git a/src/class/buffer.rs b/src/class/buffer.rs index 99a382020c0..89b0a880bbe 100644 --- a/src/class/buffer.rs +++ b/src/class/buffer.rs @@ -8,16 +8,6 @@ use crate::callback::IntoPyCallbackOutput; use crate::{ffi, PyCell, PyClass, PyRefMut}; use std::os::raw::c_int; -#[cfg(Py_LIMITED_API)] -#[derive(Clone, Default)] -pub struct PyBufferProcs { - pub bf_getbuffer: Option, - pub bf_releasebuffer: Option, -} - -#[cfg(not(Py_LIMITED_API))] -pub use ffi::PyBufferProcs; - /// Buffer protocol interface /// /// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html) @@ -47,55 +37,46 @@ pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> { type Result: IntoPyCallbackOutput<()>; } -/// Set functions used by `#[pyproto]`. +/// Extension trait for proc-macro backend. #[doc(hidden)] -impl PyBufferProcs { - pub fn set_getbuffer(&mut self) +pub trait PyBufferSlots { + fn get_getbuffer() -> ffi::getbufferproc where - T: for<'p> PyBufferGetBufferProtocol<'p>, + Self: for<'p> PyBufferGetBufferProtocol<'p>, { - self.bf_getbuffer = bf_getbuffer::(); - } - pub fn set_releasebuffer(&mut self) - where - T: for<'p> PyBufferReleaseBufferProtocol<'p>, - { - self.bf_releasebuffer = bf_releasebuffer::(); - } -} + unsafe extern "C" fn wrap( + 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::>(slf); + T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).convert(py) + }) + } -fn bf_getbuffer() -> Option -where - T: for<'p> PyBufferGetBufferProtocol<'p>, -{ - unsafe extern "C" fn wrap( - 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::>(slf); - T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).convert(py) - }) + wrap:: } - Some(wrap::) -} -fn bf_releasebuffer() -> Option -where - T: for<'p> PyBufferReleaseBufferProtocol<'p>, -{ - unsafe extern "C" fn wrap(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer) + fn get_releasebuffer() -> ffi::releasebufferproc where - T: for<'p> PyBufferReleaseBufferProtocol<'p>, + Self: for<'p> PyBufferReleaseBufferProtocol<'p>, { - crate::callback_body!(py, { - let slf = py.from_borrowed_ptr::>(slf); - T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).convert(py) - }) + unsafe extern "C" fn wrap(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::>(slf); + T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).convert(py) + }) + } + + wrap:: } - Some(wrap::) } + +impl<'p, T> PyBufferSlots for T where T: PyBufferProtocol<'p> {} diff --git a/src/class/descr.rs b/src/class/descr.rs index 2c6a7009413..6f65dfee0af 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -8,6 +8,7 @@ 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)] @@ -88,7 +89,7 @@ pub trait PyDescrSlots { { ffi::PyType_Slot { slot: ffi::Py_tp_descr_set, - pfunc: py_ternarys_func!(PyDescrSetProtocol, Self::__set__) as _, + pfunc: py_ternarys_func!(PyDescrSetProtocol, Self::__set__, c_int) as _, } } } diff --git a/src/class/number.rs b/src/class/number.rs index b095da9a777..edc5ae63c43 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -825,17 +825,17 @@ pub trait PyNumberSlots { } } - fn get_pos() -> ffi::PyType_Slot + fn get_pos() -> ffi::PyType_Slot where Self: for<'p> PyNumberPosProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_nb_absolute, + slot: ffi::Py_nb_positive, pfunc: py_unary_func!(PyNumberPosProtocol, Self::__pos__) as _, } } - fn get_abs() -> ffi::PyType_Slot + fn get_abs() -> ffi::PyType_Slot where Self: for<'p> PyNumberAbsProtocol<'p>, { @@ -845,7 +845,7 @@ pub trait PyNumberSlots { } } - fn get_invert() -> ffi::PyType_Slot + fn get_invert() -> ffi::PyType_Slot where Self: for<'p> PyNumberInvertProtocol<'p>, { diff --git a/src/class/proto_methods.rs b/src/class/proto_methods.rs index 6093018b74f..09a6d966b77 100644 --- a/src/class/proto_methods.rs +++ b/src/class/proto_methods.rs @@ -1,5 +1,12 @@ -use crate::class::buffer::PyBufferProcs; use crate::ffi; +#[cfg(not(Py_LIMITED_API))] +use crate::ffi::PyBufferProcs; + +/// ABI3 doesn't have buffer APIs, so here we define the empty one. +#[cfg(Py_LIMITED_API)] +#[doc(hidden)] +#[derive(Clone)] +pub struct PyBufferProcs; // Note(kngwyu): default implementations are for rust-numpy. Please don't remove them. pub trait PyProtoMethods { @@ -17,21 +24,33 @@ pub enum PyProtoMethodDef { Buffer(PyBufferProcs), } +impl From> for PyProtoMethodDef { + fn from(slots: Vec) -> Self { + PyProtoMethodDef::Slots(slots) + } +} + +impl From for PyProtoMethodDef { + fn from(buffer_procs: PyBufferProcs) -> Self { + PyProtoMethodDef::Buffer(buffer_procs) + } +} + #[doc(hidden)] #[cfg(feature = "macros")] -pub trait PyProtoMethodsInventory: inventory::Collect { +pub trait PyProtoInventory: inventory::Collect { fn new(methods: PyProtoMethodDef) -> Self; fn get(&'static self) -> &'static PyProtoMethodDef; } #[doc(hidden)] #[cfg(feature = "macros")] -pub trait HasProtoMethodsInventory { - type ProtoMethods: PyProtoMethodsInventory; +pub trait HasProtoInventory { + type ProtoMethods: PyProtoInventory; } #[cfg(feature = "macros")] -impl PyProtoMethods for T { +impl PyProtoMethods for T { fn get_type_slots() -> Vec { inventory::iter:: .into_iter() diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index 78cc552e322..b474e5d955f 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -13,17 +13,6 @@ use crate::derive_utils::TryFromPyCell; use crate::err::PyResult; use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python}; -#[cfg(Py_LIMITED_API)] -#[derive(Clone, Default)] -pub struct PyAsyncMethods { - pub am_await: Option, - pub am_aiter: Option, - pub am_anext: Option, -} - -#[cfg(not(Py_LIMITED_API))] -pub use ffi::PyAsyncMethods; - /// Python Async/Await support interface. /// /// Each method in this trait corresponds to Python async/await implementation. @@ -114,7 +103,7 @@ pub trait PyAsyncSlots { Self: for<'p> PyAsyncAiterProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_am_await, + slot: ffi::Py_am_aiter, pfunc: py_unarys_func!(PyAsyncAiterProtocol, Self::__aiter__) as _, } } diff --git a/src/class/sequence.rs b/src/class/sequence.rs index ccbc35ace88..449d0fbc069 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -8,45 +8,6 @@ use crate::conversion::{FromPyObject, IntoPy}; use crate::err::PyErr; use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject}; use std::os::raw::c_int; -#[cfg(Py_LIMITED_API)] -use std::os::raw::c_void; - -#[cfg(Py_LIMITED_API)] -#[derive(Clone)] -pub struct PySequenceMethods { - pub sq_length: Option, - pub sq_concat: Option, - pub sq_repeat: Option, - pub sq_item: Option, - #[allow(dead_code)] - pub was_sq_slice: *mut c_void, - pub sq_ass_item: Option, - #[allow(dead_code)] - pub was_sq_ass_slice: *mut c_void, - pub sq_contains: Option, - pub sq_inplace_concat: Option, - pub sq_inplace_repeat: Option, -} - -#[cfg(not(Py_LIMITED_API))] -pub use ffi::PySequenceMethods; - -impl Default for PySequenceMethods { - fn default() -> Self { - Self { - sq_length: None, - sq_concat: None, - sq_repeat: None, - sq_item: None, - was_sq_slice: std::ptr::null_mut(), - sq_ass_item: None, - was_sq_ass_slice: std::ptr::null_mut(), - sq_contains: None, - sq_inplace_concat: None, - sq_inplace_repeat: None, - } - } -} /// Sequence interface #[allow(unused_variables)] @@ -184,7 +145,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceConcatProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_concat, pfunc: py_binary_func!(PySequenceConcatProtocol, Self::__concat__) as _, } } @@ -193,7 +154,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceRepeatProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_repeat, pfunc: py_ssizearg_func!(PySequenceRepeatProtocol, Self::__repeat__) as _, } } @@ -202,7 +163,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceGetItemProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_item, pfunc: py_ssizearg_func!(PySequenceGetItemProtocol, Self::__getitem__) as _, } } @@ -211,7 +172,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceSetItemProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_ass_item, pfunc: sq_ass_item_impl::set_item::() as _, } } @@ -220,7 +181,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceDelItemProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_ass_item, pfunc: sq_ass_item_impl::del_item::() as _, } } @@ -229,7 +190,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_ass_item, pfunc: sq_ass_item_impl::set_del_item::() as _, } } @@ -238,7 +199,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceContainsProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_contains, pfunc: py_binary_func!(PySequenceContainsProtocol, Self::__contains__, c_int) as _, } } @@ -247,7 +208,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceInplaceConcatProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_inplace_concat, pfunc: py_binary_func!( PySequenceInplaceConcatProtocol, Self::__inplace_concat__, @@ -261,7 +222,7 @@ pub trait PySequenceSlots { Self: for<'p> PySequenceInplaceRepeatProtocol<'p>, { ffi::PyType_Slot { - slot: ffi::Py_sq_length, + slot: ffi::Py_sq_inplace_repeat, pfunc: py_ssizearg_func!( PySequenceInplaceRepeatProtocol, Self::__inplace_repeat__, From 16ad3bf676e0a8d103dd241d3cd121df63061b18 Mon Sep 17 00:00:00 2001 From: kngwyu Date: Tue, 27 Oct 2020 00:43:26 +0900 Subject: [PATCH 3/3] Use TypedSlot as internal representation of ffi::PyType_Slot --- pyo3-derive-backend/src/defs.rs | 4 +- pyo3-derive-backend/src/pyproto.rs | 9 +- src/class/basic.rs | 201 +++++----- src/class/descr.rs | 21 +- src/class/gc.rs | 104 ++--- src/class/iter.rs | 21 +- src/class/mapping.rs | 53 +-- src/class/number.rs | 614 ++++++++++++++--------------- src/class/proto_methods.rs | 4 + src/class/pyasync.rs | 31 +- src/class/sequence.rs | 178 ++++----- 11 files changed, 589 insertions(+), 651 deletions(-) diff --git a/pyo3-derive-backend/src/defs.rs b/pyo3-derive-backend/src/defs.rs index 6a1d628c8b6..eda87b5f013 100644 --- a/pyo3-derive-backend/src/defs.rs +++ b/pyo3-derive-backend/src/defs.rs @@ -158,7 +158,7 @@ pub const OBJECT: Proto = Proto { SlotGetter::new(&["__repr__"], "get_repr"), SlotGetter::new(&["__hash__"], "get_hash"), SlotGetter::new(&["__getattr__"], "get_getattr"), - SlotGetter::new(&["__richcmp__"], "get_richcompare"), + SlotGetter::new(&["__richcmp__"], "get_richcmp"), SlotGetter::new(&["__setattr__", "__delattr__"], "get_setdelattr"), SlotGetter::new(&["__setattr__"], "get_setattr"), SlotGetter::new(&["__delattr__"], "get_delattr"), @@ -381,7 +381,7 @@ pub const MAPPING: Proto = Proto { "pyo3::class::mapping::PyMappingReversedProtocolImpl", )], slot_getters: &[ - SlotGetter::new(&["__len__"], "get_length"), + SlotGetter::new(&["__len__"], "get_len"), SlotGetter::new(&["__getitem__"], "get_getitem"), SlotGetter::new(&["__setitem__", "__delitem__"], "get_setdelitem"), SlotGetter::new(&["__setitem__"], "get_setitem"), diff --git a/pyo3-derive-backend/src/pyproto.rs b/pyo3-derive-backend/src/pyproto.rs index fe60e7a14fa..249301af0cc 100644 --- a/pyo3-derive-backend/src/pyproto.rs +++ b/pyo3-derive-backend/src/pyproto.rs @@ -138,7 +138,7 @@ fn submit_protocol_methods( return Ok(quote! {}); } let ext_trait: syn::Path = syn::parse_str(proto.extension_trait)?; - let mut tokens: Vec = vec![]; + let mut tokens = vec![]; if proto.name == "Buffer" { // For buffer, we construct `PyProtoMethods` from PyBufferProcs tokens.push(quote! { @@ -154,9 +154,12 @@ fn submit_protocol_methods( tokens.push(quote! { let mut proto_methods = vec![]; }); for getter in proto.slot_getters(method_names) { let get = syn::Ident::new(getter, Span::call_site()); - tokens.push(quote! { proto_methods.push(<#ty as #ext_trait>::#get()); }); + tokens.push(quote! { + let slot = <#ty as #ext_trait>::#get(); + proto_methods.push(pyo3::ffi::PyType_Slot { slot: slot.0, pfunc: slot.1 as _ }); + }); } - } + }; if tokens.len() <= 1 { return Ok(quote! {}); } diff --git a/src/class/basic.rs b/src/class/basic.rs index 24ff4135eb6..505946d59ef 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -8,6 +8,7 @@ //! Parts of the documentation are copied from the respective methods from the //! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html) +use super::proto_methods::TypedSlot; use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput}; use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject, PyResult}; use std::os::raw::c_int; @@ -136,167 +137,147 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> { /// Extension trait for proc-macro backend. #[doc(hidden)] pub trait PyBasicSlots { - fn get_str() -> ffi::PyType_Slot + fn get_str() -> TypedSlot where Self: for<'p> PyObjectStrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_str, - pfunc: py_unary_func!(PyObjectStrProtocol, Self::__str__) as _, - } + TypedSlot( + ffi::Py_tp_str, + py_unary_func!(PyObjectStrProtocol, Self::__str__), + ) } - fn get_repr() -> ffi::PyType_Slot + fn get_repr() -> TypedSlot where Self: for<'p> PyObjectReprProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_repr, - pfunc: py_unary_func!(PyObjectReprProtocol, Self::__repr__) as _, - } + TypedSlot( + ffi::Py_tp_repr, + py_unary_func!(PyObjectReprProtocol, Self::__repr__), + ) } - fn get_hash() -> ffi::PyType_Slot + fn get_hash() -> TypedSlot 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 _, - } + TypedSlot( + ffi::Py_tp_hash, + py_unary_func!(PyObjectHashProtocol, Self::__hash__, ffi::Py_hash_t), + ) } - fn get_getattr() -> ffi::PyType_Slot + fn get_getattr() -> TypedSlot where Self: for<'p> PyObjectGetAttrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_getattro, - pfunc: tp_getattro::() as _, + unsafe extern "C" fn wrap( + 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::>(slf); + let arg = py.from_borrowed_ptr::(arg); + call_ref!(slf, __getattr__, arg).convert(py) + }) } + TypedSlot(ffi::Py_tp_getattro, wrap::) } - fn get_richcompare() -> ffi::PyType_Slot + fn get_richcmp() -> TypedSlot where Self: for<'p> PyObjectRichcmpProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_richcompare, - pfunc: tp_richcompare::() as _, + fn extract_op(op: c_int) -> PyResult { + 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(exceptions::PyValueError::new_err( + "tp_richcompare called with invalid comparison operator", + )), + } + } + unsafe extern "C" fn wrap( + 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::>(slf); + let arg = extract_or_return_not_implemented!(py, arg); + let op = extract_op(op)?; + + slf.try_borrow()?.__richcmp__(arg, op).convert(py) + }) } + TypedSlot(ffi::Py_tp_richcompare, wrap::) } - fn get_setattr() -> ffi::PyType_Slot + fn get_setattr() -> TypedSlot where Self: for<'p> PyObjectSetAttrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_setattro, - pfunc: py_func_set!(PyObjectSetAttrProtocol, Self::__setattr__) as _, - } + TypedSlot( + ffi::Py_tp_setattro, + py_func_set!(PyObjectSetAttrProtocol, Self::__setattr__), + ) } - fn get_delattr() -> ffi::PyType_Slot + fn get_delattr() -> TypedSlot where Self: for<'p> PyObjectDelAttrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_setattro, - pfunc: py_func_del!(PyObjectDelAttrProtocol, Self::__delattr__) as _, - } + TypedSlot( + ffi::Py_tp_setattro, + py_func_del!(PyObjectDelAttrProtocol, Self::__delattr__), + ) } - fn get_setdelattr() -> ffi::PyType_Slot + fn get_setdelattr() -> TypedSlot where Self: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_setattro, - pfunc: py_func_set_del!( + TypedSlot( + ffi::Py_tp_setattro, + py_func_set_del!( PyObjectSetAttrProtocol, PyObjectDelAttrProtocol, Self, __setattr__, __delattr__ - ) as _, - } + ), + ) } - fn get_bool() -> ffi::PyType_Slot + fn get_bool() -> TypedSlot where Self: for<'p> PyObjectBoolProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_bool, - pfunc: py_unary_func!(PyObjectBoolProtocol, Self::__bool__, c_int) as _, - } + TypedSlot( + ffi::Py_nb_bool, + py_unary_func!(PyObjectBoolProtocol, Self::__bool__, c_int), + ) } } impl<'p, T> PyBasicSlots for T where T: PyObjectProtocol<'p> {} - -fn tp_getattro() -> ffi::binaryfunc -where - T: for<'p> PyObjectGetAttrProtocol<'p>, -{ - unsafe extern "C" fn wrap( - 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::>(slf); - let arg = py.from_borrowed_ptr::(arg); - call_ref!(slf, __getattr__, arg).convert(py) - }) - } - wrap:: -} - -fn tp_richcompare() -> ffi::richcmpfunc -where - T: for<'p> PyObjectRichcmpProtocol<'p>, -{ - fn extract_op(op: c_int) -> PyResult { - 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(exceptions::PyValueError::new_err( - "tp_richcompare called with invalid comparison operator", - )), - } - } - unsafe extern "C" fn wrap( - 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::>(slf); - let arg = extract_or_return_not_implemented!(py, arg); - let op = extract_op(op)?; - - slf.try_borrow()?.__richcmp__(arg, op).convert(py) - }) - } - wrap:: -} diff --git a/src/class/descr.rs b/src/class/descr.rs index 6f65dfee0af..036ff881990 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -5,6 +5,7 @@ //! [Python information]( //! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors) +use super::proto_methods::TypedSlot; use crate::callback::IntoPyCallbackOutput; use crate::types::PyAny; use crate::{ffi, FromPyObject, PyClass, PyObject}; @@ -73,24 +74,24 @@ pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> { /// Extension trait for our proc-macro backend. #[doc(hidden)] pub trait PyDescrSlots { - fn get_descr_get() -> ffi::PyType_Slot + fn get_descr_get() -> TypedSlot where Self: for<'p> PyDescrGetProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_descr_get, - pfunc: py_ternarys_func!(PyDescrGetProtocol, Self::__get__) as _, - } + TypedSlot( + ffi::Py_tp_descr_get, + py_ternarys_func!(PyDescrGetProtocol, Self::__get__), + ) } - fn get_descr_set() -> ffi::PyType_Slot + fn get_descr_set() -> TypedSlot where Self: for<'p> PyDescrSetProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_descr_set, - pfunc: py_ternarys_func!(PyDescrSetProtocol, Self::__set__, c_int) as _, - } + TypedSlot( + ffi::Py_tp_descr_set, + py_ternarys_func!(PyDescrSetProtocol, Self::__set__, c_int), + ) } } diff --git a/src/class/gc.rs b/src/class/gc.rs index 08965df398a..9d8db1e096e 100644 --- a/src/class/gc.rs +++ b/src/class/gc.rs @@ -3,6 +3,7 @@ //! Python GC support //! +use super::proto_methods::TypedSlot; use crate::{ffi, AsPyPointer, PyCell, PyClass, Python}; use std::os::raw::{c_int, c_void}; @@ -21,23 +22,57 @@ pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {} /// Extension trait for proc-macro backend. #[doc(hidden)] pub trait PyGCSlots { - fn get_traverse() -> ffi::PyType_Slot + fn get_traverse() -> TypedSlot where Self: for<'p> PyGCTraverseProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_traverse, - pfunc: tp_traverse::() as _, + unsafe extern "C" fn wrap( + 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::>(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 + } } + + TypedSlot(ffi::Py_tp_traverse, wrap::) } - fn get_clear() -> ffi::PyType_Slot + + fn get_clear() -> TypedSlot where Self: for<'p> PyGCClearProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_clear, - pfunc: tp_clear::() as _, + unsafe extern "C" fn wrap(slf: *mut ffi::PyObject) -> c_int + where + T: for<'p> PyGCClearProtocol<'p>, + { + let pool = crate::GILPool::new(); + let slf = pool.python().from_borrowed_ptr::>(slf); + + slf.borrow_mut().__clear__(); + 0 } + + TypedSlot(ffi::Py_tp_clear, wrap::) } } @@ -68,56 +103,3 @@ impl<'p> PyVisit<'p> { } } } - -fn tp_traverse() -> ffi::traverseproc -where - T: for<'p> PyGCTraverseProtocol<'p>, -{ - unsafe extern "C" fn tp_traverse( - 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::>(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 - } - } - - tp_traverse:: -} - -fn tp_clear() -> ffi::inquiry -where - T: for<'p> PyGCClearProtocol<'p>, -{ - unsafe extern "C" fn tp_clear(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::>(slf); - - slf.borrow_mut().__clear__(); - 0 - } - tp_clear:: -} diff --git a/src/class/iter.rs b/src/class/iter.rs index e53dcc97638..c08bef0a215 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -2,6 +2,7 @@ //! Python Iterator Interface. //! Trait and support implementation for implementing iterators +use super::proto_methods::TypedSlot; use crate::callback::IntoPyCallbackOutput; use crate::derive_utils::TryFromPyCell; use crate::err::PyResult; @@ -74,23 +75,23 @@ pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> { /// Extension trait for proc-macro backend. #[doc(hidden)] pub trait PyIterSlots { - fn get_iter() -> ffi::PyType_Slot + fn get_iter() -> TypedSlot where Self: for<'p> PyIterIterProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_iter, - pfunc: py_unarys_func!(PyIterIterProtocol, Self::__iter__) as _, - } + TypedSlot( + ffi::Py_tp_iter, + py_unarys_func!(PyIterIterProtocol, Self::__iter__), + ) } - fn get_iternext() -> ffi::PyType_Slot + fn get_iternext() -> TypedSlot where Self: for<'p> PyIterNextProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_tp_iternext, - pfunc: py_unarys_func!(PyIterNextProtocol, Self::__next__) as _, - } + TypedSlot( + ffi::Py_tp_iternext, + py_unarys_func!(PyIterNextProtocol, Self::__next__), + ) } } diff --git a/src/class/mapping.rs b/src/class/mapping.rs index 07ee4122262..df3cfe14828 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -3,6 +3,7 @@ //! Python Mapping Interface //! Trait and support implementation for implementing mapping support +use super::proto_methods::TypedSlot; use crate::callback::IntoPyCallbackOutput; use crate::{exceptions, ffi, FromPyObject, PyClass, PyObject}; @@ -75,60 +76,60 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> { /// Extension trait for proc-macro backend. #[doc(hidden)] pub trait PyMappingSlots { - fn get_length() -> ffi::PyType_Slot + fn get_len() -> TypedSlot where Self: for<'p> PyMappingLenProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_mp_length, - pfunc: py_len_func!(PyMappingLenProtocol, Self::__len__) as _, - } + TypedSlot( + ffi::Py_mp_length, + py_len_func!(PyMappingLenProtocol, Self::__len__), + ) } - fn get_getitem() -> ffi::PyType_Slot + fn get_getitem() -> TypedSlot where Self: for<'p> PyMappingGetItemProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_mp_subscript, - pfunc: py_binary_func!(PyMappingGetItemProtocol, Self::__getitem__) as _, - } + TypedSlot( + ffi::Py_mp_subscript, + py_binary_func!(PyMappingGetItemProtocol, Self::__getitem__), + ) } - fn get_setitem() -> ffi::PyType_Slot + fn get_setitem() -> TypedSlot where Self: for<'p> PyMappingSetItemProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_mp_ass_subscript, - pfunc: py_func_set!(PyMappingSetItemProtocol, Self::__setitem__) as _, - } + TypedSlot( + ffi::Py_mp_ass_subscript, + py_func_set!(PyMappingSetItemProtocol, Self::__setitem__), + ) } - fn get_delitem() -> ffi::PyType_Slot + fn get_delitem() -> TypedSlot where Self: for<'p> PyMappingDelItemProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_mp_ass_subscript, - pfunc: py_func_del!(PyMappingDelItemProtocol, Self::__delitem__) as _, - } + TypedSlot( + ffi::Py_mp_ass_subscript, + py_func_del!(PyMappingDelItemProtocol, Self::__delitem__), + ) } - fn get_setdelitem() -> ffi::PyType_Slot + fn get_setdelitem() -> TypedSlot where Self: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_mp_ass_subscript, - pfunc: py_func_set_del!( + TypedSlot( + ffi::Py_mp_ass_subscript, + py_func_set_del!( PyMappingSetItemProtocol, PyMappingDelItemProtocol, Self, __setitem__, __delitem__ - ) as _, - } + ), + ) } } diff --git a/src/class/number.rs b/src/class/number.rs index edc5ae63c43..cdcea6b0a58 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -2,6 +2,7 @@ //! Python Number Interface //! Trait and support implementation for implementing number protocol +use super::proto_methods::TypedSlot; use crate::callback::IntoPyCallbackOutput; use crate::err::PyErr; use crate::{ffi, FromPyObject, PyClass, PyObject}; @@ -581,153 +582,153 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> { /// Extension trait for proc-macro backend. #[doc(hidden)] pub trait PyNumberSlots { - fn get_add_radd() -> ffi::PyType_Slot + fn get_add_radd() -> TypedSlot where Self: for<'p> PyNumberAddProtocol<'p> + for<'p> PyNumberRAddProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_add, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_add, + py_binary_fallback_num_func!( Self, PyNumberAddProtocol::__add__, PyNumberRAddProtocol::__radd__ - ) as _, - } + ), + ) } - fn get_add() -> ffi::PyType_Slot + fn get_add() -> TypedSlot where Self: for<'p> PyNumberAddProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_add, - pfunc: py_binary_num_func!(PyNumberAddProtocol, Self::__add__) as _, - } + TypedSlot( + ffi::Py_nb_add, + py_binary_num_func!(PyNumberAddProtocol, Self::__add__), + ) } - fn get_radd() -> ffi::PyType_Slot + fn get_radd() -> TypedSlot where Self: for<'p> PyNumberRAddProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_add, - pfunc: py_binary_reversed_num_func!(PyNumberRAddProtocol, Self::__radd__) as _, - } + TypedSlot( + ffi::Py_nb_add, + py_binary_reversed_num_func!(PyNumberRAddProtocol, Self::__radd__), + ) } - fn get_sub_rsub() -> ffi::PyType_Slot + fn get_sub_rsub() -> TypedSlot where Self: for<'p> PyNumberSubProtocol<'p> + for<'p> PyNumberRSubProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_subtract, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_subtract, + py_binary_fallback_num_func!( Self, PyNumberSubProtocol::__sub__, PyNumberRSubProtocol::__rsub__ - ) as _, - } + ), + ) } - fn get_sub() -> ffi::PyType_Slot + fn get_sub() -> TypedSlot where Self: for<'p> PyNumberSubProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_subtract, - pfunc: py_binary_num_func!(PyNumberSubProtocol, Self::__sub__) as _, - } + TypedSlot( + ffi::Py_nb_subtract, + py_binary_num_func!(PyNumberSubProtocol, Self::__sub__), + ) } - fn get_rsub() -> ffi::PyType_Slot + fn get_rsub() -> TypedSlot where Self: for<'p> PyNumberRSubProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_subtract, - pfunc: py_binary_reversed_num_func!(PyNumberRSubProtocol, Self::__rsub__) as _, - } + TypedSlot( + ffi::Py_nb_subtract, + py_binary_reversed_num_func!(PyNumberRSubProtocol, Self::__rsub__), + ) } - fn get_mul_rmul() -> ffi::PyType_Slot + fn get_mul_rmul() -> TypedSlot where Self: for<'p> PyNumberMulProtocol<'p> + for<'p> PyNumberRMulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_multiply, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_multiply, + py_binary_fallback_num_func!( Self, PyNumberMulProtocol::__mul__, PyNumberRMulProtocol::__rmul__ - ) as _, - } + ), + ) } - fn get_mul() -> ffi::PyType_Slot + fn get_mul() -> TypedSlot where Self: for<'p> PyNumberMulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_multiply, - pfunc: py_binary_num_func!(PyNumberMulProtocol, Self::__mul__) as _, - } + TypedSlot( + ffi::Py_nb_multiply, + py_binary_num_func!(PyNumberMulProtocol, Self::__mul__), + ) } - fn get_rmul() -> ffi::PyType_Slot + fn get_rmul() -> TypedSlot where Self: for<'p> PyNumberRMulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_multiply, - pfunc: py_binary_reversed_num_func!(PyNumberRMulProtocol, Self::__rmul__) as _, - } + TypedSlot( + ffi::Py_nb_multiply, + py_binary_reversed_num_func!(PyNumberRMulProtocol, Self::__rmul__), + ) } - fn get_mod() -> ffi::PyType_Slot + fn get_mod() -> TypedSlot where Self: for<'p> PyNumberModProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_remainder, - pfunc: py_binary_num_func!(PyNumberModProtocol, Self::__mod__) as _, - } + TypedSlot( + ffi::Py_nb_remainder, + py_binary_num_func!(PyNumberModProtocol, Self::__mod__), + ) } - fn get_divmod_rdivmod() -> ffi::PyType_Slot + fn get_divmod_rdivmod() -> TypedSlot where Self: for<'p> PyNumberDivmodProtocol<'p> + for<'p> PyNumberRDivmodProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_divmod, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_divmod, + py_binary_fallback_num_func!( Self, PyNumberDivmodProtocol::__divmod__, PyNumberRDivmodProtocol::__rdivmod__ - ) as _, - } + ), + ) } - fn get_divmod() -> ffi::PyType_Slot + fn get_divmod() -> TypedSlot where Self: for<'p> PyNumberDivmodProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_divmod, - pfunc: py_binary_num_func!(PyNumberDivmodProtocol, Self::__divmod__) as _, - } + TypedSlot( + ffi::Py_nb_divmod, + py_binary_num_func!(PyNumberDivmodProtocol, Self::__divmod__), + ) } - fn get_rdivmod() -> ffi::PyType_Slot + fn get_rdivmod() -> TypedSlot where Self: for<'p> PyNumberRDivmodProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_divmod, - pfunc: py_binary_reversed_num_func!(PyNumberRDivmodProtocol, Self::__rdivmod__) as _, - } + TypedSlot( + ffi::Py_nb_divmod, + py_binary_reversed_num_func!(PyNumberRDivmodProtocol, Self::__rdivmod__), + ) } - fn get_pow_rpow() -> ffi::PyType_Slot + fn get_pow_rpow() -> TypedSlot where Self: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>, { @@ -757,13 +758,10 @@ pub trait PyNumberSlots { }) } - ffi::PyType_Slot { - slot: ffi::Py_nb_power, - pfunc: wrap_pow_and_rpow:: as _, - } + TypedSlot(ffi::Py_nb_power, wrap_pow_and_rpow::) } - fn get_pow() -> ffi::PyType_Slot + fn get_pow() -> TypedSlot where Self: for<'p> PyNumberPowProtocol<'p>, { @@ -783,13 +781,10 @@ pub trait PyNumberSlots { }) } - ffi::PyType_Slot { - slot: ffi::Py_nb_power, - pfunc: wrap_pow:: as _, - } + TypedSlot(ffi::Py_nb_power, wrap_pow::) } - fn get_rpow() -> ffi::PyType_Slot + fn get_rpow() -> TypedSlot where Self: for<'p> PyNumberRPowProtocol<'p>, { @@ -809,283 +804,280 @@ pub trait PyNumberSlots { }) } - ffi::PyType_Slot { - slot: ffi::Py_nb_power, - pfunc: wrap_rpow:: as _, - } + TypedSlot(ffi::Py_nb_power, wrap_rpow::) } - fn get_neg() -> ffi::PyType_Slot + fn get_neg() -> TypedSlot where Self: for<'p> PyNumberNegProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_negative, - pfunc: py_unary_func!(PyNumberNegProtocol, Self::__neg__) as _, - } + TypedSlot( + ffi::Py_nb_negative, + py_unary_func!(PyNumberNegProtocol, Self::__neg__), + ) } - fn get_pos() -> ffi::PyType_Slot + fn get_pos() -> TypedSlot where Self: for<'p> PyNumberPosProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_positive, - pfunc: py_unary_func!(PyNumberPosProtocol, Self::__pos__) as _, - } + TypedSlot( + ffi::Py_nb_positive, + py_unary_func!(PyNumberPosProtocol, Self::__pos__), + ) } - fn get_abs() -> ffi::PyType_Slot + fn get_abs() -> TypedSlot where Self: for<'p> PyNumberAbsProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_absolute, - pfunc: py_unary_func!(PyNumberAbsProtocol, Self::__abs__) as _, - } + TypedSlot( + ffi::Py_nb_absolute, + py_unary_func!(PyNumberAbsProtocol, Self::__abs__), + ) } - fn get_invert() -> ffi::PyType_Slot + fn get_invert() -> TypedSlot where Self: for<'p> PyNumberInvertProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_invert, - pfunc: py_unary_func!(PyNumberInvertProtocol, Self::__invert__) as _, - } + TypedSlot( + ffi::Py_nb_invert, + py_unary_func!(PyNumberInvertProtocol, Self::__invert__), + ) } - fn get_lshift_rlshift() -> ffi::PyType_Slot + fn get_lshift_rlshift() -> TypedSlot where Self: for<'p> PyNumberLShiftProtocol<'p> + for<'p> PyNumberRLShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_lshift, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_lshift, + py_binary_fallback_num_func!( Self, PyNumberLShiftProtocol::__lshift__, PyNumberRLShiftProtocol::__rlshift__ - ) as _, - } + ), + ) } - fn get_lshift() -> ffi::PyType_Slot + fn get_lshift() -> TypedSlot where Self: for<'p> PyNumberLShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_lshift, - pfunc: py_binary_num_func!(PyNumberLShiftProtocol, Self::__lshift__) as _, - } + TypedSlot( + ffi::Py_nb_lshift, + py_binary_num_func!(PyNumberLShiftProtocol, Self::__lshift__), + ) } - fn get_rlshift() -> ffi::PyType_Slot + fn get_rlshift() -> TypedSlot where Self: for<'p> PyNumberRLShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_lshift, - pfunc: py_binary_reversed_num_func!(PyNumberRLShiftProtocol, Self::__rlshift__) as _, - } + TypedSlot( + ffi::Py_nb_lshift, + py_binary_reversed_num_func!(PyNumberRLShiftProtocol, Self::__rlshift__), + ) } - fn get_rshift_rrshift() -> ffi::PyType_Slot + fn get_rshift_rrshift() -> TypedSlot where Self: for<'p> PyNumberRShiftProtocol<'p> + for<'p> PyNumberRRShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_rshift, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_rshift, + py_binary_fallback_num_func!( Self, PyNumberRShiftProtocol::__rshift__, PyNumberRRShiftProtocol::__rrshift__ - ) as _, - } + ), + ) } - fn get_rshift() -> ffi::PyType_Slot + fn get_rshift() -> TypedSlot where Self: for<'p> PyNumberRShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_rshift, - pfunc: py_binary_num_func!(PyNumberRShiftProtocol, Self::__rshift__) as _, - } + TypedSlot( + ffi::Py_nb_rshift, + py_binary_num_func!(PyNumberRShiftProtocol, Self::__rshift__), + ) } - fn get_rrshift() -> ffi::PyType_Slot + fn get_rrshift() -> TypedSlot where Self: for<'p> PyNumberRRShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_rshift, - pfunc: py_binary_reversed_num_func!(PyNumberRRShiftProtocol, Self::__rrshift__) as _, - } + TypedSlot( + ffi::Py_nb_rshift, + py_binary_reversed_num_func!(PyNumberRRShiftProtocol, Self::__rrshift__), + ) } - fn get_and_rand() -> ffi::PyType_Slot + fn get_and_rand() -> TypedSlot where Self: for<'p> PyNumberAndProtocol<'p> + for<'p> PyNumberRAndProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_and, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_and, + py_binary_fallback_num_func!( Self, PyNumberAndProtocol::__and__, PyNumberRAndProtocol::__rand__ - ) as _, - } + ), + ) } - fn get_and() -> ffi::PyType_Slot + fn get_and() -> TypedSlot where Self: for<'p> PyNumberAndProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_and, - pfunc: py_binary_num_func!(PyNumberAndProtocol, Self::__and__) as _, - } + TypedSlot( + ffi::Py_nb_and, + py_binary_num_func!(PyNumberAndProtocol, Self::__and__), + ) } - fn get_rand() -> ffi::PyType_Slot + fn get_rand() -> TypedSlot where Self: for<'p> PyNumberRAndProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_and, - pfunc: py_binary_reversed_num_func!(PyNumberRAndProtocol, Self::__rand__) as _, - } + TypedSlot( + ffi::Py_nb_and, + py_binary_reversed_num_func!(PyNumberRAndProtocol, Self::__rand__), + ) } - fn get_xor_rxor() -> ffi::PyType_Slot + fn get_xor_rxor() -> TypedSlot where Self: for<'p> PyNumberXorProtocol<'p> + for<'p> PyNumberRXorProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_xor, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_xor, + py_binary_fallback_num_func!( Self, PyNumberXorProtocol::__xor__, PyNumberRXorProtocol::__rxor__ - ) as _, - } + ), + ) } - fn get_xor() -> ffi::PyType_Slot + fn get_xor() -> TypedSlot where Self: for<'p> PyNumberXorProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_xor, - pfunc: py_binary_num_func!(PyNumberXorProtocol, Self::__xor__) as _, - } + TypedSlot( + ffi::Py_nb_xor, + py_binary_num_func!(PyNumberXorProtocol, Self::__xor__), + ) } - fn get_rxor() -> ffi::PyType_Slot + fn get_rxor() -> TypedSlot where Self: for<'p> PyNumberRXorProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_xor, - pfunc: py_binary_reversed_num_func!(PyNumberRXorProtocol, Self::__rxor__) as _, - } + TypedSlot( + ffi::Py_nb_xor, + py_binary_reversed_num_func!(PyNumberRXorProtocol, Self::__rxor__), + ) } - fn get_or_ror() -> ffi::PyType_Slot + fn get_or_ror() -> TypedSlot where Self: for<'p> PyNumberOrProtocol<'p> + for<'p> PyNumberROrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_or, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_or, + py_binary_fallback_num_func!( Self, PyNumberOrProtocol::__or__, PyNumberROrProtocol::__ror__ - ) as _, - } + ), + ) } - fn get_or() -> ffi::PyType_Slot + fn get_or() -> TypedSlot where Self: for<'p> PyNumberOrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_or, - pfunc: py_binary_num_func!(PyNumberOrProtocol, Self::__or__) as _, - } + TypedSlot( + ffi::Py_nb_or, + py_binary_num_func!(PyNumberOrProtocol, Self::__or__), + ) } - fn get_ror() -> ffi::PyType_Slot + fn get_ror() -> TypedSlot where Self: for<'p> PyNumberROrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_or, - pfunc: py_binary_reversed_num_func!(PyNumberROrProtocol, Self::__ror__) as _, - } + TypedSlot( + ffi::Py_nb_or, + py_binary_reversed_num_func!(PyNumberROrProtocol, Self::__ror__), + ) } - fn get_int() -> ffi::PyType_Slot + fn get_int() -> TypedSlot where Self: for<'p> PyNumberIntProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_int, - pfunc: py_unary_func!(PyNumberIntProtocol, Self::__int__) as _, - } + TypedSlot( + ffi::Py_nb_int, + py_unary_func!(PyNumberIntProtocol, Self::__int__), + ) } - fn get_float() -> ffi::PyType_Slot + fn get_float() -> TypedSlot where Self: for<'p> PyNumberFloatProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_float, - pfunc: py_unary_func!(PyNumberFloatProtocol, Self::__float__) as _, - } + TypedSlot( + ffi::Py_nb_float, + py_unary_func!(PyNumberFloatProtocol, Self::__float__), + ) } - fn get_iadd() -> ffi::PyType_Slot + fn get_iadd() -> TypedSlot where Self: for<'p> PyNumberIAddProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_add, - pfunc: py_binary_self_func!(PyNumberIAddProtocol, Self::__iadd__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_add, + py_binary_self_func!(PyNumberIAddProtocol, Self::__iadd__), + ) } - fn get_isub() -> ffi::PyType_Slot + fn get_isub() -> TypedSlot where Self: for<'p> PyNumberISubProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_subtract, - pfunc: py_binary_self_func!(PyNumberISubProtocol, Self::__isub__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_subtract, + py_binary_self_func!(PyNumberISubProtocol, Self::__isub__), + ) } - fn get_imul() -> ffi::PyType_Slot + fn get_imul() -> TypedSlot where Self: for<'p> PyNumberIMulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_multiply, - pfunc: py_binary_self_func!(PyNumberIMulProtocol, Self::__imul__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_multiply, + py_binary_self_func!(PyNumberIMulProtocol, Self::__imul__), + ) } - fn get_imod() -> ffi::PyType_Slot + fn get_imod() -> TypedSlot where Self: for<'p> PyNumberIModProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_remainder, - pfunc: py_binary_self_func!(PyNumberIModProtocol, Self::__imod__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_remainder, + py_binary_self_func!(PyNumberIModProtocol, Self::__imod__), + ) } - fn get_ipow() -> ffi::PyType_Slot + fn get_ipow() -> TypedSlot where Self: for<'p> PyNumberIPowProtocol<'p>, { @@ -1108,203 +1100,199 @@ pub trait PyNumberSlots { }) } - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_power, - pfunc: wrap_ipow:: as _, - } + TypedSlot(ffi::Py_nb_inplace_power, wrap_ipow::) } - fn get_ilshift() -> ffi::PyType_Slot + fn get_ilshift() -> TypedSlot where Self: for<'p> PyNumberILShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_lshift, - pfunc: py_binary_self_func!(PyNumberILShiftProtocol, Self::__ilshift__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_lshift, + py_binary_self_func!(PyNumberILShiftProtocol, Self::__ilshift__), + ) } - fn get_irshift() -> ffi::PyType_Slot + fn get_irshift() -> TypedSlot where Self: for<'p> PyNumberIRShiftProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_rshift, - pfunc: py_binary_self_func!(PyNumberIRShiftProtocol, Self::__irshift__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_rshift, + py_binary_self_func!(PyNumberIRShiftProtocol, Self::__irshift__), + ) } - fn get_iand() -> ffi::PyType_Slot + fn get_iand() -> TypedSlot where Self: for<'p> PyNumberIAndProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_and, - pfunc: py_binary_self_func!(PyNumberIAndProtocol, Self::__iand__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_and, + py_binary_self_func!(PyNumberIAndProtocol, Self::__iand__), + ) } - fn get_ixor() -> ffi::PyType_Slot + fn get_ixor() -> TypedSlot where Self: for<'p> PyNumberIXorProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_xor, - pfunc: py_binary_self_func!(PyNumberIXorProtocol, Self::__ixor__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_xor, + py_binary_self_func!(PyNumberIXorProtocol, Self::__ixor__), + ) } - fn get_ior() -> ffi::PyType_Slot + fn get_ior() -> TypedSlot where Self: for<'p> PyNumberIOrProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_or, - pfunc: py_binary_self_func!(PyNumberIOrProtocol, Self::__ior__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_or, + py_binary_self_func!(PyNumberIOrProtocol, Self::__ior__), + ) } - fn get_floordiv_rfloordiv() -> ffi::PyType_Slot + fn get_floordiv_rfloordiv() -> TypedSlot where Self: for<'p> PyNumberFloordivProtocol<'p> + for<'p> PyNumberRFloordivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_floor_divide, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_floor_divide, + py_binary_fallback_num_func!( Self, PyNumberFloordivProtocol::__floordiv__, PyNumberRFloordivProtocol::__rfloordiv__ - ) as _, - } + ), + ) } - fn get_floordiv() -> ffi::PyType_Slot + fn get_floordiv() -> TypedSlot where Self: for<'p> PyNumberFloordivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_floor_divide, - pfunc: py_binary_num_func!(PyNumberFloordivProtocol, Self::__floordiv__) as _, - } + TypedSlot( + ffi::Py_nb_floor_divide, + py_binary_num_func!(PyNumberFloordivProtocol, Self::__floordiv__), + ) } - fn get_rfloordiv() -> ffi::PyType_Slot + fn get_rfloordiv() -> TypedSlot where Self: for<'p> PyNumberRFloordivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_floor_divide, - pfunc: py_binary_reversed_num_func!(PyNumberRFloordivProtocol, Self::__rfloordiv__) - as _, - } + TypedSlot( + ffi::Py_nb_floor_divide, + py_binary_reversed_num_func!(PyNumberRFloordivProtocol, Self::__rfloordiv__), + ) } - fn get_truediv_rtruediv() -> ffi::PyType_Slot + fn get_truediv_rtruediv() -> TypedSlot where Self: for<'p> PyNumberTruedivProtocol<'p> + for<'p> PyNumberRTruedivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_true_divide, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_true_divide, + py_binary_fallback_num_func!( Self, PyNumberTruedivProtocol::__truediv__, PyNumberRTruedivProtocol::__rtruediv__ - ) as _, - } + ), + ) } - fn get_truediv() -> ffi::PyType_Slot + fn get_truediv() -> TypedSlot where Self: for<'p> PyNumberTruedivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_true_divide, - pfunc: py_binary_num_func!(PyNumberTruedivProtocol, Self::__truediv__) as _, - } + TypedSlot( + ffi::Py_nb_true_divide, + py_binary_num_func!(PyNumberTruedivProtocol, Self::__truediv__), + ) } - fn get_rtruediv() -> ffi::PyType_Slot + fn get_rtruediv() -> TypedSlot where Self: for<'p> PyNumberRTruedivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_true_divide, - pfunc: py_binary_reversed_num_func!(PyNumberRTruedivProtocol, Self::__rtruediv__) as _, - } + TypedSlot( + ffi::Py_nb_true_divide, + py_binary_reversed_num_func!(PyNumberRTruedivProtocol, Self::__rtruediv__), + ) } - fn get_ifloordiv() -> ffi::PyType_Slot + fn get_ifloordiv() -> TypedSlot where Self: for<'p> PyNumberIFloordivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_floor_divide, - pfunc: py_binary_self_func!(PyNumberIFloordivProtocol, Self::__ifloordiv__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_floor_divide, + py_binary_self_func!(PyNumberIFloordivProtocol, Self::__ifloordiv__), + ) } - fn get_itruediv() -> ffi::PyType_Slot + fn get_itruediv() -> TypedSlot where Self: for<'p> PyNumberITruedivProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_true_divide, - pfunc: py_binary_self_func!(PyNumberITruedivProtocol, Self::__itruediv__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_true_divide, + py_binary_self_func!(PyNumberITruedivProtocol, Self::__itruediv__), + ) } - fn get_index() -> ffi::PyType_Slot + fn get_index() -> TypedSlot where Self: for<'p> PyNumberIndexProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_index, - pfunc: py_unary_func!(PyNumberIndexProtocol, Self::__index__) as _, - } + TypedSlot( + ffi::Py_nb_index, + py_unary_func!(PyNumberIndexProtocol, Self::__index__), + ) } - fn get_matmul_rmatmul() -> ffi::PyType_Slot + fn get_matmul_rmatmul() -> TypedSlot where Self: for<'p> PyNumberMatmulProtocol<'p> + for<'p> PyNumberRMatmulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_matrix_multiply, - pfunc: py_binary_fallback_num_func!( + TypedSlot( + ffi::Py_nb_matrix_multiply, + py_binary_fallback_num_func!( Self, PyNumberMatmulProtocol::__matmul__, PyNumberRMatmulProtocol::__rmatmul__ - ) as _, - } + ), + ) } - fn get_matmul() -> ffi::PyType_Slot + fn get_matmul() -> TypedSlot where Self: for<'p> PyNumberMatmulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_matrix_multiply, - pfunc: py_binary_num_func!(PyNumberMatmulProtocol, Self::__matmul__) as _, - } + TypedSlot( + ffi::Py_nb_matrix_multiply, + py_binary_num_func!(PyNumberMatmulProtocol, Self::__matmul__), + ) } - fn get_rmatmul() -> ffi::PyType_Slot + fn get_rmatmul() -> TypedSlot where Self: for<'p> PyNumberRMatmulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_matrix_multiply, - pfunc: py_binary_reversed_num_func!(PyNumberRMatmulProtocol, Self::__rmatmul__) as _, - } + TypedSlot( + ffi::Py_nb_matrix_multiply, + py_binary_reversed_num_func!(PyNumberRMatmulProtocol, Self::__rmatmul__), + ) } - fn get_imatmul() -> ffi::PyType_Slot + fn get_imatmul() -> TypedSlot where Self: for<'p> PyNumberIMatmulProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_nb_inplace_matrix_multiply, - pfunc: py_binary_self_func!(PyNumberIMatmulProtocol, Self::__imatmul__) as _, - } + TypedSlot( + ffi::Py_nb_inplace_matrix_multiply, + py_binary_self_func!(PyNumberIMatmulProtocol, Self::__imatmul__), + ) } } diff --git a/src/class/proto_methods.rs b/src/class/proto_methods.rs index 09a6d966b77..eff528f0873 100644 --- a/src/class/proto_methods.rs +++ b/src/class/proto_methods.rs @@ -18,6 +18,10 @@ pub trait PyProtoMethods { } } +/// Typed version of `ffi::PyType_Slot` +#[doc(hidden)] +pub struct TypedSlot(pub std::os::raw::c_int, pub T); + #[doc(hidden)] pub enum PyProtoMethodDef { Slots(Vec), diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index b474e5d955f..226656fd41a 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -8,6 +8,7 @@ //! [PEP-0492](https://www.python.org/dev/peps/pep-0492/) //! +use super::proto_methods::TypedSlot; use crate::callback::IntoPyCallbackOutput; use crate::derive_utils::TryFromPyCell; use crate::err::PyResult; @@ -88,34 +89,34 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> { /// Extension trait for proc-macro backend. #[doc(hidden)] pub trait PyAsyncSlots { - fn get_await() -> ffi::PyType_Slot + fn get_await() -> TypedSlot where Self: for<'p> PyAsyncAwaitProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_am_await, - pfunc: py_unarys_func!(PyAsyncAwaitProtocol, Self::__await__) as _, - } + TypedSlot( + ffi::Py_am_await, + py_unarys_func!(PyAsyncAwaitProtocol, Self::__await__), + ) } - fn get_aiter() -> ffi::PyType_Slot + fn get_aiter() -> TypedSlot where Self: for<'p> PyAsyncAiterProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_am_aiter, - pfunc: py_unarys_func!(PyAsyncAiterProtocol, Self::__aiter__) as _, - } + TypedSlot( + ffi::Py_am_aiter, + py_unarys_func!(PyAsyncAiterProtocol, Self::__aiter__), + ) } - fn get_anext() -> ffi::PyType_Slot + fn get_anext() -> TypedSlot where Self: for<'p> PyAsyncAnextProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_am_anext, - pfunc: py_unarys_func!(PyAsyncAnextProtocol, Self::__anext__) as _, - } + TypedSlot( + ffi::Py_am_anext, + py_unarys_func!(PyAsyncAnextProtocol, Self::__anext__), + ) } } diff --git a/src/class/sequence.rs b/src/class/sequence.rs index 449d0fbc069..7ac3ffd9637 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -3,6 +3,7 @@ //! Python Sequence Interface //! Trait and support implementation for implementing sequence +use super::proto_methods::TypedSlot; use crate::callback::IntoPyCallbackOutput; use crate::conversion::{FromPyObject, IntoPy}; use crate::err::PyErr; @@ -131,118 +132,49 @@ pub trait PySequenceInplaceRepeatProtocol<'p>: /// Extension trait for proc-macro backend. #[doc(hidden)] pub trait PySequenceSlots { - fn get_len() -> ffi::PyType_Slot + fn get_len() -> TypedSlot where Self: for<'p> PySequenceLenProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_sq_length, - pfunc: py_len_func!(PySequenceLenProtocol, Self::__len__) as _, - } + TypedSlot( + ffi::Py_sq_length, + py_len_func!(PySequenceLenProtocol, Self::__len__), + ) } - fn get_concat() -> ffi::PyType_Slot + + fn get_concat() -> TypedSlot where Self: for<'p> PySequenceConcatProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_sq_concat, - pfunc: py_binary_func!(PySequenceConcatProtocol, Self::__concat__) as _, - } + TypedSlot( + ffi::Py_sq_concat, + py_binary_func!(PySequenceConcatProtocol, Self::__concat__), + ) } - fn get_repeat() -> ffi::PyType_Slot + + fn get_repeat() -> TypedSlot where Self: for<'p> PySequenceRepeatProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_sq_repeat, - pfunc: py_ssizearg_func!(PySequenceRepeatProtocol, Self::__repeat__) as _, - } + TypedSlot( + ffi::Py_sq_repeat, + py_ssizearg_func!(PySequenceRepeatProtocol, Self::__repeat__), + ) } - fn get_getitem() -> ffi::PyType_Slot + + fn get_getitem() -> TypedSlot where Self: for<'p> PySequenceGetItemProtocol<'p>, { - ffi::PyType_Slot { - slot: ffi::Py_sq_item, - pfunc: py_ssizearg_func!(PySequenceGetItemProtocol, Self::__getitem__) as _, - } - } - fn get_setitem() -> ffi::PyType_Slot - where - Self: for<'p> PySequenceSetItemProtocol<'p>, - { - ffi::PyType_Slot { - slot: ffi::Py_sq_ass_item, - pfunc: sq_ass_item_impl::set_item::() as _, - } - } - fn get_delitem() -> ffi::PyType_Slot - where - Self: for<'p> PySequenceDelItemProtocol<'p>, - { - ffi::PyType_Slot { - slot: ffi::Py_sq_ass_item, - pfunc: sq_ass_item_impl::del_item::() as _, - } - } - fn get_setdelitem() -> ffi::PyType_Slot - where - Self: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>, - { - ffi::PyType_Slot { - slot: ffi::Py_sq_ass_item, - pfunc: sq_ass_item_impl::set_del_item::() as _, - } - } - fn get_contains() -> ffi::PyType_Slot - where - Self: for<'p> PySequenceContainsProtocol<'p>, - { - ffi::PyType_Slot { - slot: ffi::Py_sq_contains, - pfunc: py_binary_func!(PySequenceContainsProtocol, Self::__contains__, c_int) as _, - } - } - fn get_inplace_concat() -> ffi::PyType_Slot - where - Self: for<'p> PySequenceInplaceConcatProtocol<'p>, - { - ffi::PyType_Slot { - slot: ffi::Py_sq_inplace_concat, - pfunc: py_binary_func!( - PySequenceInplaceConcatProtocol, - Self::__inplace_concat__, - *mut ffi::PyObject, - call_mut - ) as _, - } - } - fn get_inplace_repeat() -> ffi::PyType_Slot - where - Self: for<'p> PySequenceInplaceRepeatProtocol<'p>, - { - ffi::PyType_Slot { - slot: ffi::Py_sq_inplace_repeat, - pfunc: py_ssizearg_func!( - PySequenceInplaceRepeatProtocol, - Self::__inplace_repeat__, - call_mut - ) as _, - } + TypedSlot( + ffi::Py_sq_item, + py_ssizearg_func!(PySequenceGetItemProtocol, Self::__getitem__), + ) } -} - -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() -> ffi::ssizeobjargproc + fn get_setitem() -> TypedSlot where - T: for<'p> PySequenceSetItemProtocol<'p>, + Self: for<'p> PySequenceSetItemProtocol<'p>, { unsafe extern "C" fn wrap( slf: *mut ffi::PyObject, @@ -268,12 +200,13 @@ mod sq_ass_item_impl { crate::callback::convert(py, slf.__setitem__(key.into(), value)) }) } - wrap:: + + TypedSlot(ffi::Py_sq_ass_item, wrap::) } - pub(super) fn del_item() -> ffi::ssizeobjargproc + fn get_delitem() -> TypedSlot where - T: for<'p> PySequenceDelItemProtocol<'p>, + Self: for<'p> PySequenceDelItemProtocol<'p>, { unsafe extern "C" fn wrap( slf: *mut ffi::PyObject, @@ -296,12 +229,13 @@ mod sq_ass_item_impl { } }) } - wrap:: + + TypedSlot(ffi::Py_sq_ass_item, wrap::) } - pub(super) fn set_del_item() -> ffi::ssizeobjargproc + fn get_setdelitem() -> TypedSlot where - T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>, + Self: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>, { unsafe extern "C" fn wrap( slf: *mut ffi::PyObject, @@ -324,6 +258,48 @@ mod sq_ass_item_impl { } }) } - wrap:: + + TypedSlot(ffi::Py_sq_ass_item, wrap::) + } + + fn get_contains() -> TypedSlot + where + Self: for<'p> PySequenceContainsProtocol<'p>, + { + TypedSlot( + ffi::Py_sq_contains, + py_binary_func!(PySequenceContainsProtocol, Self::__contains__, c_int), + ) + } + + fn get_inplace_concat() -> TypedSlot + where + Self: for<'p> PySequenceInplaceConcatProtocol<'p>, + { + TypedSlot( + ffi::Py_sq_inplace_concat, + py_binary_func!( + PySequenceInplaceConcatProtocol, + Self::__inplace_concat__, + *mut ffi::PyObject, + call_mut + ), + ) + } + + fn get_inplace_repeat() -> TypedSlot + where + Self: for<'p> PySequenceInplaceRepeatProtocol<'p>, + { + TypedSlot( + ffi::Py_sq_inplace_repeat, + py_ssizearg_func!( + PySequenceInplaceRepeatProtocol, + Self::__inplace_repeat__, + call_mut + ), + ) } } + +impl<'p, T> PySequenceSlots for T where T: PySequenceProtocol<'p> {}