diff --git a/pyo3-derive-backend/src/defs.rs b/pyo3-derive-backend/src/defs.rs index 0bdfedf9915..6199a722b8c 100644 --- a/pyo3-derive-backend/src/defs.rs +++ b/pyo3-derive-backend/src/defs.rs @@ -171,7 +171,7 @@ pub const OBJECT: Proto = Proto { pub const ASYNC: Proto = Proto { name: "Async", - slot_table: "pyo3::ffi::PyAsyncMethods", + slot_table: "pyo3::class::pyasync::PyAsyncMethods", set_slot_table: "set_async_methods", methods: &[ MethodProto::UnaryS { @@ -220,7 +220,7 @@ pub const ASYNC: Proto = Proto { pub const BUFFER: Proto = Proto { name: "Buffer", - slot_table: "pyo3::ffi::PyBufferProcs", + slot_table: "pyo3::class::buffer::PyBufferProcs", set_slot_table: "set_buffer_methods", methods: &[ MethodProto::Unary { @@ -358,7 +358,7 @@ pub const ITER: Proto = Proto { pub const MAPPING: Proto = Proto { name: "Mapping", - slot_table: "pyo3::ffi::PyMappingMethods", + slot_table: "pyo3::class::mapping::PyMappingMethods", set_slot_table: "set_mapping_methods", methods: &[ MethodProto::Unary { @@ -401,7 +401,7 @@ pub const MAPPING: Proto = Proto { pub const SEQ: Proto = Proto { name: "Sequence", - slot_table: "pyo3::ffi::PySequenceMethods", + slot_table: "pyo3::class::sequence::PySequenceMethods", set_slot_table: "set_sequence_methods", methods: &[ MethodProto::Unary { @@ -467,7 +467,7 @@ pub const SEQ: Proto = Proto { pub const NUM: Proto = Proto { name: "Number", - slot_table: "pyo3::ffi::PyNumberMethods", + slot_table: "pyo3::class::number::PyNumberMethods", set_slot_table: "set_number_methods", methods: &[ MethodProto::BinaryS { diff --git a/src/class/basic.rs b/src/class/basic.rs index cd7bc713b8b..37ca5275717 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -9,9 +9,8 @@ //! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html) use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput}; -use crate::pyclass::maybe_push_slot; use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult}; -use std::os::raw::{c_int, c_void}; +use std::os::raw::c_int; /// Operators for the __richcmp__ method #[derive(Debug)] @@ -148,39 +147,6 @@ pub struct PyObjectMethods { #[doc(hidden)] impl PyObjectMethods { - pub(crate) fn update_slots(&self, slots: &mut Vec) { - maybe_push_slot(slots, ffi::Py_tp_str, self.tp_str.map(|v| v as *mut c_void)); - maybe_push_slot( - slots, - ffi::Py_tp_repr, - self.tp_repr.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_tp_hash, - self.tp_hash.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_tp_getattro, - self.tp_getattro.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_tp_richcompare, - self.tp_richcompare.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_tp_setattro, - self.tp_setattro.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_bool, - self.nb_bool.map(|v| v as *mut c_void), - ); - } // Set functions used by `#[pyproto]`. pub fn set_str(&mut self) where @@ -242,6 +208,16 @@ impl PyObjectMethods { { 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 _)); + } } fn tp_getattro() -> Option diff --git a/src/class/buffer.rs b/src/class/buffer.rs index f2977274b9f..99a382020c0 100644 --- a/src/class/buffer.rs +++ b/src/class/buffer.rs @@ -5,12 +5,19 @@ //! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html) //! c-api use crate::callback::IntoPyCallbackOutput; -use crate::{ - ffi::{self, PyBufferProcs}, - PyCell, PyClass, PyRefMut, -}; +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) diff --git a/src/class/descr.rs b/src/class/descr.rs index 3ff50e8896e..88fb4dc50cd 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -6,10 +6,9 @@ //! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors) use crate::callback::IntoPyCallbackOutput; -use crate::pyclass::maybe_push_slot; use crate::types::PyAny; use crate::{ffi, FromPyObject, PyClass, PyObject}; -use std::os::raw::{c_int, c_void}; +use std::os::raw::c_int; /// Descriptor interface #[allow(unused_variables)] @@ -80,18 +79,6 @@ pub struct PyDescrMethods { #[doc(hidden)] impl PyDescrMethods { - pub(crate) fn update_slots(&self, slots: &mut Vec) { - maybe_push_slot( - slots, - ffi::Py_tp_descr_get, - self.tp_descr_get.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_tp_descr_set, - self.tp_descr_set.map(|v| v as *mut c_void), - ); - } pub fn set_descr_get(&mut self) where T: for<'p> PyDescrGetProtocol<'p>, @@ -104,4 +91,8 @@ impl PyDescrMethods { { 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 _)); + } } diff --git a/src/class/gc.rs b/src/class/gc.rs index d6a29be7ea1..d600e663f5b 100644 --- a/src/class/gc.rs +++ b/src/class/gc.rs @@ -3,7 +3,6 @@ //! Python GC support //! -use crate::pyclass::maybe_push_slot; use crate::{ffi, AsPyPointer, PyCell, PyClass, Python}; use std::os::raw::{c_int, c_void}; @@ -28,17 +27,9 @@ pub struct PyGCMethods { #[doc(hidden)] impl PyGCMethods { - pub(crate) fn update_slots(&self, slots: &mut Vec) { - maybe_push_slot( - slots, - ffi::Py_tp_traverse, - self.tp_traverse.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_tp_clear, - self.tp_clear.map(|v| v as *mut c_void), - ); + 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) @@ -57,7 +48,7 @@ impl PyGCMethods { } /// Object visitor for GC. -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct PyVisit<'p> { visit: ffi::visitproc, arg: *mut c_void, diff --git a/src/class/iter.rs b/src/class/iter.rs index 1ac2475c8a7..8c2934bb9aa 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -5,9 +5,7 @@ use crate::callback::IntoPyCallbackOutput; use crate::derive_utils::TryFromPyCell; use crate::err::PyResult; -use crate::pyclass::maybe_push_slot; use crate::{ffi, IntoPy, IntoPyPointer, PyClass, PyObject, Python}; -use std::os::raw::c_void; /// Python Iterator Interface. /// @@ -81,18 +79,6 @@ pub struct PyIterMethods { #[doc(hidden)] impl PyIterMethods { - pub(crate) fn update_slots(&self, slots: &mut Vec) { - maybe_push_slot( - slots, - ffi::Py_tp_iter, - self.tp_iter.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_tp_iternext, - self.tp_iternext.map(|v| v as *mut c_void), - ); - } pub fn set_iter(&mut self) where T: for<'p> PyIterIterProtocol<'p>, @@ -105,6 +91,10 @@ impl PyIterMethods { { 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 _)); + } } /// Output of `__next__` which can either `yield` the next value in the iteration, or diff --git a/src/class/mapping.rs b/src/class/mapping.rs index d20547e18b8..61969883fab 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -7,6 +7,17 @@ use crate::callback::IntoPyCallbackOutput; use crate::err::PyErr; 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 { @@ -74,7 +85,7 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> { } #[doc(hidden)] -impl ffi::PyMappingMethods { +impl PyMappingMethods { pub fn set_length(&mut self) where T: for<'p> PyMappingLenProtocol<'p>, @@ -111,4 +122,12 @@ impl ffi::PyMappingMethods { __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 _), + ); + } } diff --git a/src/class/number.rs b/src/class/number.rs index 6d6c3255365..8843587a49a 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -2,11 +2,98 @@ //! Python Number Interface //! Trait and support implementation for implementing number protocol - use crate::callback::IntoPyCallbackOutput; use crate::err::PyErr; use crate::{ffi, FromPyObject, PyClass, PyObject}; +#[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, + 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)] pub trait PyNumberProtocol<'p>: PyClass { @@ -580,7 +667,7 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> { } #[doc(hidden)] -impl ffi::PyNumberMethods { +impl PyNumberMethods { pub fn set_add_radd(&mut self) where T: for<'p> PyNumberAddProtocol<'p> + for<'p> PyNumberRAddProtocol<'p>, @@ -1068,4 +1155,74 @@ impl ffi::PyNumberMethods { 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 _), + ); + } } diff --git a/src/class/proto_methods.rs b/src/class/proto_methods.rs index 76e75d9f440..d28d1522cca 100644 --- a/src/class/proto_methods.rs +++ b/src/class/proto_methods.rs @@ -1,8 +1,7 @@ use crate::class::{ - basic::PyObjectMethods, descr::PyDescrMethods, gc::PyGCMethods, iter::PyIterMethods, -}; -use crate::ffi::{ - PyAsyncMethods, PyBufferProcs, PyMappingMethods, PyNumberMethods, PySequenceMethods, + basic::PyObjectMethods, buffer::PyBufferProcs, descr::PyDescrMethods, gc::PyGCMethods, + iter::PyIterMethods, mapping::PyMappingMethods, number::PyNumberMethods, + pyasync::PyAsyncMethods, sequence::PySequenceMethods, }; use std::{ ptr::{self, NonNull}, diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index 82548835c7f..cbc67ae004a 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -13,6 +13,17 @@ 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. @@ -86,7 +97,7 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> { } #[doc(hidden)] -impl ffi::PyAsyncMethods { +impl PyAsyncMethods { pub fn set_await(&mut self) where T: for<'p> PyAsyncAwaitProtocol<'p>, @@ -105,6 +116,12 @@ impl ffi::PyAsyncMethods { { 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 _)); + } } pub enum IterANextOutput { diff --git a/src/class/sequence.rs b/src/class/sequence.rs index a9c62f03d0b..3d2e29f201a 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -9,6 +9,41 @@ use crate::err::PyErr; use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject}; use std::os::raw::c_int; +#[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, + pub was_sq_slice: *mut c_void, + pub sq_ass_item: Option, + 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)] pub trait PySequenceProtocol<'p>: PyClass + Sized { @@ -129,7 +164,7 @@ pub trait PySequenceInplaceRepeatProtocol<'p>: } #[doc(hidden)] -impl ffi::PySequenceMethods { +impl PySequenceMethods { pub fn set_len(&mut self) where T: for<'p> PySequenceLenProtocol<'p>, @@ -199,6 +234,23 @@ impl ffi::PySequenceMethods { 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 _), + ); + } } /// It can be possible to delete and set items (PySequenceSetItemProtocol and diff --git a/src/ffi/descrobject.rs b/src/ffi/descrobject.rs index 828b85c941d..0651eee59b9 100644 --- a/src/ffi/descrobject.rs +++ b/src/ffi/descrobject.rs @@ -7,7 +7,6 @@ use std::os::raw::{c_char, c_int, c_void}; use std::ptr; pub type getter = unsafe extern "C" fn(slf: *mut PyObject, closure: *mut c_void) -> *mut PyObject; - pub type setter = unsafe extern "C" fn(slf: *mut PyObject, value: *mut PyObject, closure: *mut c_void) -> c_int; diff --git a/src/ffi/object.rs b/src/ffi/object.rs index d4f1b8d8676..80c9278d3fd 100644 --- a/src/ffi/object.rs +++ b/src/ffi/object.rs @@ -314,69 +314,14 @@ mod typeobject { pub nb_inplace_matrix_multiply: Option, } - impl Default for PyNumberMethods { - #[inline] - fn default() -> Self { - PyNumberMethods_INIT - } - } macro_rules! as_expr { ($e:expr) => { $e }; } - macro_rules! py_number_methods_init { - ($($tail:tt)*) => { - as_expr! { - PyNumberMethods { - 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, - $($tail)* - } - } - } - } - - pub const PyNumberMethods_INIT: PyNumberMethods = py_number_methods_init! { - nb_matrix_multiply: None, - nb_inplace_matrix_multiply: None, - }; - #[repr(C)] - #[derive(Copy, Clone)] + #[derive(Clone)] pub struct PySequenceMethods { pub sq_length: Option, pub sq_concat: Option, @@ -390,83 +335,29 @@ mod typeobject { pub sq_inplace_repeat: Option, } - impl Default for PySequenceMethods { - #[inline] - fn default() -> Self { - unsafe { mem::zeroed() } - } - } - pub const PySequenceMethods_INIT: PySequenceMethods = PySequenceMethods { - sq_length: None, - sq_concat: None, - sq_repeat: None, - sq_item: None, - was_sq_slice: ptr::null_mut(), - sq_ass_item: None, - was_sq_ass_slice: ptr::null_mut(), - sq_contains: None, - sq_inplace_concat: None, - sq_inplace_repeat: None, - }; #[repr(C)] - #[derive(Copy, Clone)] + #[derive(Clone, Default)] pub struct PyMappingMethods { pub mp_length: Option, pub mp_subscript: Option, pub mp_ass_subscript: Option, } - impl Default for PyMappingMethods { - #[inline] - fn default() -> Self { - unsafe { mem::zeroed() } - } - } - pub const PyMappingMethods_INIT: PyMappingMethods = PyMappingMethods { - mp_length: None, - mp_subscript: None, - mp_ass_subscript: None, - }; #[repr(C)] - #[derive(Copy, Clone)] + #[derive(Clone, Default)] pub struct PyAsyncMethods { pub am_await: Option, pub am_aiter: Option, pub am_anext: Option, } - impl Default for PyAsyncMethods { - #[inline] - fn default() -> Self { - PyAsyncMethods_INIT - } - } - - pub const PyAsyncMethods_INIT: PyAsyncMethods = PyAsyncMethods { - am_await: None, - am_aiter: None, - am_anext: None, - }; - #[repr(C)] - #[derive(Copy, Clone, Debug)] + #[derive(Clone, Default)] pub struct PyBufferProcs { pub bf_getbuffer: Option, pub bf_releasebuffer: Option, } - impl Default for PyBufferProcs { - #[inline] - fn default() -> Self { - PyBufferProcs_INIT - } - } - - pub const PyBufferProcs_INIT: PyBufferProcs = PyBufferProcs { - bf_getbuffer: None, - bf_releasebuffer: None, - }; - #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct PyTypeObject { @@ -650,7 +541,7 @@ mod typeobject { pub const PyTypeObject_INIT: PyTypeObject = type_object_init!(); #[repr(C)] - #[derive(Copy, Clone)] + #[derive(Clone)] pub struct PyHeapTypeObject { pub ht_type: PyTypeObject, pub as_async: PyAsyncMethods, diff --git a/src/pyclass.rs b/src/pyclass.rs index a614897e101..01923544f27 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -10,7 +10,7 @@ use crate::{class, ffi, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Pytho use std::convert::TryInto; use std::ffi::CString; use std::marker::PhantomData; -use std::os::raw::{c_int, c_uint, c_void}; +use std::os::raw::{c_char, c_int, c_uint, c_void}; use std::{ptr, thread}; #[inline] @@ -108,272 +108,37 @@ pub trait PyClass: type BaseNativeType: PyTypeInfo + PyNativeType; } -pub(crate) fn maybe_push_slot( - slots: &mut Vec, - slot: c_int, - val: Option<*mut c_void>, -) { - if let Some(v) = val { - slots.push(ffi::PyType_Slot { slot, pfunc: v }); - } -} +/// For collecting slot items. +#[derive(Default)] +pub(crate) struct TypeSlots(Vec); -fn push_numbers_slots(slots: &mut Vec, numbers: &ffi::PyNumberMethods) { - maybe_push_slot( - slots, - ffi::Py_nb_add, - numbers.nb_add.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_subtract, - numbers.nb_subtract.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_multiply, - numbers.nb_multiply.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_remainder, - numbers.nb_remainder.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_divmod, - numbers.nb_divmod.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_power, - numbers.nb_power.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_negative, - numbers.nb_negative.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_positive, - numbers.nb_positive.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_absolute, - numbers.nb_absolute.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_bool, - numbers.nb_bool.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_invert, - numbers.nb_invert.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_lshift, - numbers.nb_lshift.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_rshift, - numbers.nb_rshift.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_and, - numbers.nb_and.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_xor, - numbers.nb_xor.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_or, - numbers.nb_or.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_int, - numbers.nb_int.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_float, - numbers.nb_float.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_add, - numbers.nb_inplace_add.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_subtract, - numbers.nb_inplace_subtract.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_multiply, - numbers.nb_inplace_multiply.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_remainder, - numbers.nb_inplace_remainder.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_power, - numbers.nb_inplace_power.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_lshift, - numbers.nb_inplace_lshift.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_rshift, - numbers.nb_inplace_rshift.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_and, - numbers.nb_inplace_and.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_xor, - numbers.nb_inplace_xor.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_or, - numbers.nb_inplace_or.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_floor_divide, - numbers.nb_floor_divide.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_true_divide, - numbers.nb_true_divide.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_floor_divide, - numbers.nb_inplace_floor_divide.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_true_divide, - numbers.nb_inplace_true_divide.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_index, - numbers.nb_index.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_matrix_multiply, - numbers.nb_matrix_multiply.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_nb_inplace_matrix_multiply, - numbers.nb_inplace_matrix_multiply.map(|v| v as *mut c_void), - ); +impl TypeSlots { + fn push(&mut self, slot: c_int, pfunc: *mut c_void) { + self.0.push(ffi::PyType_Slot { slot, pfunc }); + } + pub(crate) fn maybe_push(&mut self, slot: c_int, value: Option<*mut c_void>) { + value.map(|v| self.push(slot, v)); + } } -fn push_mapping_slots(slots: &mut Vec, mapping: &ffi::PyMappingMethods) { - maybe_push_slot( - slots, - ffi::Py_mp_length, - mapping.mp_length.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_mp_subscript, - mapping.mp_subscript.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_mp_ass_subscript, - mapping.mp_ass_subscript.map(|v| v as *mut c_void), - ); +fn tp_doc() -> PyResult> { + Ok(match T::DESCRIPTION { + "\0" => None, + s if s.as_bytes().ends_with(b"\0") => Some(s.as_ptr() as _), + // If the description is not null-terminated, create CString and leak it + s => Some(CString::new(s)?.into_raw() as _), + }) } -fn push_sequence_slots(slots: &mut Vec, seq: &ffi::PySequenceMethods) { - maybe_push_slot( - slots, - ffi::Py_sq_length, - seq.sq_length.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_sq_concat, - seq.sq_concat.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_sq_repeat, - seq.sq_repeat.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_sq_item, - seq.sq_item.map(|v| v as *mut c_void), - ); - - maybe_push_slot( - slots, - ffi::Py_sq_ass_item, - seq.sq_ass_item.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_sq_contains, - seq.sq_contains.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_sq_inplace_concat, - seq.sq_inplace_concat.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_sq_inplace_repeat, - seq.sq_inplace_repeat.map(|v| v as *mut c_void), - ); +fn get_type_name(module_name: Option<&str>) -> PyResult<*mut c_char> { + Ok(match module_name { + Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME))?.into_raw(), + None => CString::new(T::NAME)?.into_raw(), + }) } -fn push_async_slots(slots: &mut Vec, asnc: &ffi::PyAsyncMethods) { - maybe_push_slot( - slots, - ffi::Py_am_await, - asnc.am_await.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_am_aiter, - asnc.am_aiter.map(|v| v as *mut c_void), - ); - maybe_push_slot( - slots, - ffi::Py_am_anext, - asnc.am_anext.map(|v| v as *mut c_void), - ); +fn into_raw(vec: Vec) -> *mut c_void { + Box::into_raw(vec.into_boxed_slice()) as _ } pub(crate) fn create_type_object( @@ -383,138 +148,89 @@ pub(crate) fn create_type_object( where T: PyClass, { - let mut slots = vec![]; - - slots.push(ffi::PyType_Slot { - slot: ffi::Py_tp_base, - pfunc: T::BaseType::type_object_raw(py) as *mut c_void, - }); - - let doc = match T::DESCRIPTION { - "\0" => None, - s if s.as_bytes().ends_with(b"\0") => Some(s.as_ptr() as _), - // If the description is not null-terminated, create CString and leak it - s => Some(CString::new(s)?.into_raw() as _), - }; - maybe_push_slot(&mut slots, ffi::Py_tp_doc, doc); + let mut slots = TypeSlots::default(); - maybe_push_slot( - &mut slots, - ffi::Py_tp_dealloc, - tp_dealloc::().map(|v| v as *mut c_void), - ); + slots.push(ffi::Py_tp_base, T::BaseType::type_object_raw(py) as _); + slots.maybe_push(ffi::Py_tp_doc, tp_doc::()?); + slots.maybe_push(ffi::Py_tp_dealloc, tp_dealloc::().map(|v| v as _)); - let (new, call, mut methods) = py_class_method_defs::(); - maybe_push_slot(&mut slots, ffi::Py_tp_new, new.map(|v| v as *mut c_void)); - maybe_push_slot(&mut slots, ffi::Py_tp_call, call.map(|v| v as *mut c_void)); + 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() { - methods.push(ffi::PyMethodDef_INIT); - maybe_push_slot( - &mut slots, - ffi::Py_tp_methods, - Some(Box::into_raw(methods.into_boxed_slice()) as *mut c_void), - ); + slots.push(ffi::Py_tp_methods, into_raw(methods)); } // properties - let mut props = py_class_properties::(); - - if !T::Dict::IS_DUMMY { - props.push(ffi::PyGetSetDef_DICT); - } + let props = py_class_properties::(); if !props.is_empty() { - props.push(ffi::PyGetSetDef_INIT); - maybe_push_slot( - &mut slots, - ffi::Py_tp_getset, - Some(Box::into_raw(props.into_boxed_slice()) as *mut c_void), - ); - } - - if let Some(basic) = T::basic_methods() { - unsafe { basic.as_ref() }.update_slots(&mut slots); - } - - if let Some(number) = T::number_methods() { - push_numbers_slots(&mut slots, unsafe { number.as_ref() }); + slots.push(ffi::Py_tp_getset, into_raw(props)); } + // basic methods + T::basic_methods().map(|basic| unsafe { basic.as_ref() }.update_slots(&mut slots)); + // number methods + T::number_methods().map(|num| unsafe { num.as_ref() }.update_slots(&mut slots)); // iterator methods - if let Some(iter) = T::iter_methods() { - unsafe { iter.as_ref() }.update_slots(&mut slots); - } - + T::iter_methods().map(|iter| unsafe { iter.as_ref() }.update_slots(&mut slots)); // mapping methods - if let Some(mapping) = T::mapping_methods() { - push_mapping_slots(&mut slots, unsafe { mapping.as_ref() }); - } - + T::mapping_methods().map(|map| unsafe { map.as_ref() }.update_slots(&mut slots)); // sequence methods - if let Some(seq) = T::sequence_methods() { - push_sequence_slots(&mut slots, unsafe { seq.as_ref() }); - } - + T::sequence_methods().map(|seq| unsafe { seq.as_ref() }.update_slots(&mut slots)); // descriptor protocol - if let Some(descr) = T::descr_methods() { - unsafe { descr.as_ref() }.update_slots(&mut slots); - } - + T::descr_methods().map(|descr| unsafe { descr.as_ref() }.update_slots(&mut slots)); // async methods - if let Some(asnc) = T::async_methods() { - push_async_slots(&mut slots, unsafe { asnc.as_ref() }); - } - + T::async_methods().map(|asnc| unsafe { asnc.as_ref() }.update_slots(&mut slots)); // GC support - if let Some(gc) = T::gc_methods() { - unsafe { gc.as_ref() }.update_slots(&mut slots); - } + T::gc_methods().map(|gc| unsafe { gc.as_ref() }.update_slots(&mut slots)); - slots.push(ffi::PyType_Slot { - slot: 0, - pfunc: ptr::null_mut(), - }); + slots.push(0, ptr::null_mut()); let mut spec = ffi::PyType_Spec { - name: match module_name { - Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME))?.into_raw(), - None => CString::new(T::NAME)?.into_raw(), - }, + name: get_type_name::(module_name)?, basicsize: std::mem::size_of::() as c_int, itemsize: 0, flags: py_class_flags::(), - slots: slots.as_mut_slice().as_mut_ptr(), + slots: slots.0.as_mut_slice().as_mut_ptr(), }; let type_object = unsafe { ffi::PyType_FromSpec(&mut spec) }; if type_object.is_null() { PyErr::fetch(py).into() } else { - // Just patch the type objects for the things there's no - // PyType_FromSpec API for... there's no reason this should work, - // except for that it does and we have tests. - let mut type_object = type_object as *mut ffi::PyTypeObject; - if let Some(buffer) = T::buffer_methods() { - 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; - } + tp_init_additional::(type_object as _); + Ok(type_object as _) + } +} + +#[cfg(not(Py_LIMITED_API))] +fn tp_init_additional(type_object: *mut ffi::PyTypeObject) { + // Just patch the type objects for the things there's no + // PyType_FromSpec API for... there's no reason this should work, + // except for that it does and we have tests. + if let Some(buffer) = T::buffer_methods() { + 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; } - // __dict__ support - if let Some(dict_offset) = PyCell::::dict_offset() { - unsafe { - (*type_object).tp_dictoffset = dict_offset as ffi::Py_ssize_t; - } + } + // __dict__ support + if let Some(dict_offset) = PyCell::::dict_offset() { + unsafe { + (*type_object).tp_dictoffset = dict_offset as ffi::Py_ssize_t; } - // weakref support - if let Some(weakref_offset) = PyCell::::weakref_offset() { - unsafe { - (*type_object).tp_weaklistoffset = weakref_offset as ffi::Py_ssize_t; - } + } + // weakref support + if let Some(weakref_offset) = PyCell::::weakref_offset() { + unsafe { + (*type_object).tp_weaklistoffset = weakref_offset as ffi::Py_ssize_t; } - Ok(type_object) } } +#[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 { ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HAVE_GC @@ -581,10 +297,14 @@ fn py_class_method_defs() -> ( } } + if !defs.is_empty() { + defs.push(ffi::PyMethodDef_INIT); + } + (new, call, defs) } -fn py_class_properties() -> Vec { +fn py_class_properties() -> Vec { let mut defs = std::collections::HashMap::new(); for def in T::py_methods() { @@ -609,7 +329,11 @@ fn py_class_properties() -> Vec { } } - defs.values().cloned().collect() + let mut props: Vec<_> = defs.values().cloned().collect(); + if !T::Dict::IS_DUMMY { + props.push(ffi::PyGetSetDef_DICT); + } + props } /// This trait is implemented for `#[pyclass]` and handles following two situations: