opt: don't emit T::dict_offset and T::weakref_offset without attributes
This commit is contained in:
parent
807e126178
commit
e33b3e6a5b
|
@ -102,7 +102,7 @@ Since we need lots of boilerplate for implementing common traits for these types
|
|||
|
||||
[`src/pycell.rs`], [`src/pyclass.rs`], and [`src/type_object.rs`] contain types and
|
||||
traits to make `#[pyclass]` work.
|
||||
Also, [`src/pyclass_init.rs`] and [`src/pyclass_slots.rs`] have related functionalities.
|
||||
Also, [`src/pyclass_init.rs`] and [`src/impl_/pyclass.rs`] have related functionalities.
|
||||
|
||||
To realize object-oriented programming in C, all Python objects must have the following two fields
|
||||
at the beginning.
|
||||
|
|
|
@ -44,7 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Reduce generated LLVM code size (to improve compile times) for:
|
||||
- internal `handle_panic` helper [#2074](https://github.com/PyO3/pyo3/pull/2074)
|
||||
- `#[pyfunction]` and `#[pymethods]` argument extraction [#2075](https://github.com/PyO3/pyo3/pull/2075)
|
||||
- `#[pyclass]` type object creation [#2076](https://github.com/PyO3/pyo3/pull/2076)
|
||||
- `#[pyclass]` type object creation [#2076](https://github.com/PyO3/pyo3/pull/2076) [#2081](https://github.com/PyO3/pyo3/pull/2081)
|
||||
|
||||
### Removed
|
||||
|
||||
|
|
|
@ -838,8 +838,8 @@ unsafe impl pyo3::PyTypeInfo for MyClass {
|
|||
}
|
||||
|
||||
impl pyo3::pyclass::PyClass for MyClass {
|
||||
type Dict = pyo3::pyclass_slots::PyClassDummySlot;
|
||||
type WeakRef = pyo3::pyclass_slots::PyClassDummySlot;
|
||||
type Dict = pyo3::impl_::pyclass::PyClassDummySlot;
|
||||
type WeakRef = pyo3::impl_::pyclass::PyClassDummySlot;
|
||||
type BaseNativeType = PyAny;
|
||||
}
|
||||
|
||||
|
|
|
@ -663,16 +663,16 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
let cls = self.cls;
|
||||
let attr = self.attr;
|
||||
let dict = if attr.has_dict {
|
||||
quote! { _pyo3::pyclass_slots::PyClassDictSlot }
|
||||
quote! { _pyo3::impl_::pyclass::PyClassDictSlot }
|
||||
} else {
|
||||
quote! { _pyo3::pyclass_slots::PyClassDummySlot }
|
||||
quote! { _pyo3::impl_::pyclass::PyClassDummySlot }
|
||||
};
|
||||
|
||||
// insert space for weak ref
|
||||
let weakref = if attr.has_weaklist {
|
||||
quote! { _pyo3::pyclass_slots::PyClassWeakRefSlot }
|
||||
quote! { _pyo3::impl_::pyclass::PyClassWeakRefSlot }
|
||||
} else {
|
||||
quote! { _pyo3::pyclass_slots::PyClassDummySlot }
|
||||
quote! { _pyo3::impl_::pyclass::PyClassDummySlot }
|
||||
};
|
||||
|
||||
let base_nativetype = if attr.has_extends {
|
||||
|
@ -727,6 +727,27 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
let base = &self.attr.base;
|
||||
let is_subclass = self.attr.has_extends;
|
||||
|
||||
let dict_offset = if self.attr.has_dict {
|
||||
quote! {
|
||||
fn dict_offset() -> ::std::option::Option<_pyo3::ffi::Py_ssize_t> {
|
||||
::std::option::Option::Some(_pyo3::impl_::pyclass::dict_offset::<Self>())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
// insert space for weak ref
|
||||
let weaklist_offset = if self.attr.has_weaklist {
|
||||
quote! {
|
||||
fn weaklist_offset() -> ::std::option::Option<_pyo3::ffi::Py_ssize_t> {
|
||||
::std::option::Option::Some(_pyo3::impl_::pyclass::weaklist_offset::<Self>())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
let thread_checker = if self.attr.has_unsendable {
|
||||
quote! { _pyo3::class::impl_::ThreadCheckerImpl<#cls> }
|
||||
} else if self.attr.has_extends {
|
||||
|
@ -831,6 +852,8 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
let collector = PyClassImplCollector::<Self>::new();
|
||||
collector.buffer_procs()
|
||||
}
|
||||
#dict_offset
|
||||
#weaklist_offset
|
||||
}
|
||||
|
||||
#inventory_class
|
||||
|
|
|
@ -71,19 +71,31 @@ pub trait PyClassImpl: Sized {
|
|||
type Inventory: PyClassInventory;
|
||||
|
||||
fn for_each_method_def(_visitor: &mut dyn FnMut(&[PyMethodDefType])) {}
|
||||
fn for_each_proto_slot(_visitor: &mut dyn FnMut(&[ffi::PyType_Slot])) {}
|
||||
|
||||
#[inline]
|
||||
fn get_new() -> Option<ffi::newfunc> {
|
||||
None
|
||||
}
|
||||
#[inline]
|
||||
fn get_alloc() -> Option<ffi::allocfunc> {
|
||||
None
|
||||
}
|
||||
#[inline]
|
||||
fn get_free() -> Option<ffi::freefunc> {
|
||||
None
|
||||
}
|
||||
fn for_each_proto_slot(_visitor: &mut dyn FnMut(&[ffi::PyType_Slot])) {}
|
||||
fn get_buffer() -> Option<&'static PyBufferProcs> {
|
||||
None
|
||||
}
|
||||
#[inline]
|
||||
fn dict_offset() -> Option<ffi::Py_ssize_t> {
|
||||
None
|
||||
}
|
||||
#[inline]
|
||||
fn weaklist_offset() -> Option<ffi::Py_ssize_t> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Traits describing known special methods.
|
||||
|
|
|
@ -11,4 +11,5 @@ pub mod freelist;
|
|||
pub mod frompyobject;
|
||||
pub(crate) mod not_send;
|
||||
#[doc(hidden)]
|
||||
pub mod pyclass;
|
||||
pub mod pymodule;
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
//! Contains additional fields for `#[pyclass]`.
|
||||
//!
|
||||
//! Mainly used by PyO3's proc-macro code.
|
||||
use crate::{ffi, Python};
|
||||
use crate::{ffi, PyCell, PyClass, Python};
|
||||
|
||||
/// Gets the offset of the dictionary from the start of the object in bytes.
|
||||
#[inline]
|
||||
pub fn dict_offset<T: PyClass>() -> ffi::Py_ssize_t {
|
||||
PyCell::<T>::dict_offset()
|
||||
}
|
||||
|
||||
/// Gets the offset of the weakref list from the start of the object in bytes.
|
||||
#[inline]
|
||||
pub fn weaklist_offset<T: PyClass>() -> ffi::Py_ssize_t {
|
||||
PyCell::<T>::weaklist_offset()
|
||||
}
|
||||
|
||||
/// Represents the `__dict__` field for `#[pyclass]`.
|
||||
pub trait PyClassDict {
|
||||
/// Whether this `__dict__` field is capable of holding a dictionary.
|
||||
const IS_DUMMY: bool = true;
|
||||
/// Initializes a [PyObject](crate::ffi::PyObject) `__dict__` reference.
|
||||
fn new() -> Self;
|
||||
/// Empties the dictionary of its key-value pairs.
|
||||
|
@ -17,8 +24,6 @@ pub trait PyClassDict {
|
|||
|
||||
/// Represents the `__weakref__` field for `#[pyclass]`.
|
||||
pub trait PyClassWeakRef {
|
||||
/// Whether this `weakref` type is capable of holding weak references.
|
||||
const IS_DUMMY: bool = true;
|
||||
/// Initializes a `weakref` instance.
|
||||
fn new() -> Self;
|
||||
/// Clears the weak references to the given object.
|
||||
|
@ -58,7 +63,6 @@ pub struct PyClassDictSlot(*mut ffi::PyObject);
|
|||
|
||||
impl PyClassDict for PyClassDictSlot {
|
||||
private_impl! {}
|
||||
const IS_DUMMY: bool = false;
|
||||
#[inline]
|
||||
fn new() -> Self {
|
||||
Self(std::ptr::null_mut())
|
||||
|
@ -79,7 +83,6 @@ pub struct PyClassWeakRefSlot(*mut ffi::PyObject);
|
|||
|
||||
impl PyClassWeakRef for PyClassWeakRefSlot {
|
||||
private_impl! {}
|
||||
const IS_DUMMY: bool = false;
|
||||
#[inline]
|
||||
fn new() -> Self {
|
||||
Self(std::ptr::null_mut())
|
|
@ -337,7 +337,6 @@ pub mod prelude;
|
|||
pub mod pycell;
|
||||
pub mod pyclass;
|
||||
pub mod pyclass_init;
|
||||
pub mod pyclass_slots;
|
||||
mod python;
|
||||
pub mod type_object;
|
||||
pub mod types;
|
||||
|
|
146
src/pycell.rs
146
src/pycell.rs
|
@ -175,9 +175,9 @@
|
|||
//! [Interior Mutability]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html "RefCell<T> and the Interior Mutability Pattern - The Rust Programming Language"
|
||||
|
||||
use crate::exceptions::PyRuntimeError;
|
||||
use crate::impl_::pyclass::{PyClassDict, PyClassWeakRef};
|
||||
use crate::pyclass::PyClass;
|
||||
use crate::pyclass_init::PyClassInitializer;
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::type_object::{PyLayout, PySizedLayout};
|
||||
use crate::types::PyAny;
|
||||
use crate::{class::impl_::PyClassBaseType, class::impl_::PyClassThreadChecker};
|
||||
|
@ -253,84 +253,6 @@ pub(crate) struct PyCellContents<T: PyClass> {
|
|||
pub(crate) weakref: T::WeakRef,
|
||||
}
|
||||
|
||||
impl<T: PyClass> PyCell<T> {
|
||||
/// Get the offset of the dictionary from the start of the struct in bytes.
|
||||
#[cfg(not(all(Py_LIMITED_API, not(Py_3_9))))]
|
||||
pub(crate) fn dict_offset() -> Option<ffi::Py_ssize_t> {
|
||||
use std::convert::TryInto;
|
||||
if T::Dict::IS_DUMMY {
|
||||
None
|
||||
} else {
|
||||
#[cfg(addr_of)]
|
||||
let offset = {
|
||||
// With std::ptr::addr_of - can measure offset using uninit memory without UB.
|
||||
let cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
let base_ptr = cell.as_ptr();
|
||||
let dict_ptr = unsafe { std::ptr::addr_of!((*base_ptr).contents.dict) };
|
||||
unsafe { (dict_ptr as *const u8).offset_from(base_ptr as *const u8) }
|
||||
};
|
||||
#[cfg(not(addr_of))]
|
||||
let offset = {
|
||||
// No std::ptr::addr_of - need to take references to PyCell to measure offsets;
|
||||
// make a zero-initialised "fake" one so that referencing it is not UB.
|
||||
let mut cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
std::ptr::write_bytes(cell.as_mut_ptr(), 0, 1);
|
||||
}
|
||||
let cell = unsafe { cell.assume_init() };
|
||||
let dict_ptr = &cell.contents.dict;
|
||||
// offset_from wasn't stabilised until 1.47, so we also have to work around
|
||||
// that...
|
||||
let offset = (dict_ptr as *const _ as usize) - (&cell as *const _ as usize);
|
||||
// This isn't a valid cell, so ensure no Drop code runs etc.
|
||||
std::mem::forget(cell);
|
||||
offset
|
||||
};
|
||||
// Py_ssize_t may not be equal to isize on all platforms
|
||||
#[allow(clippy::useless_conversion)]
|
||||
Some(offset.try_into().expect("offset should fit in Py_ssize_t"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the offset of the weakref list from the start of the struct in bytes.
|
||||
#[cfg(not(all(Py_LIMITED_API, not(Py_3_9))))]
|
||||
pub(crate) fn weakref_offset() -> Option<ffi::Py_ssize_t> {
|
||||
use std::convert::TryInto;
|
||||
if T::WeakRef::IS_DUMMY {
|
||||
None
|
||||
} else {
|
||||
#[cfg(addr_of)]
|
||||
let offset = {
|
||||
// With std::ptr::addr_of - can measure offset using uninit memory without UB.
|
||||
let cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
let base_ptr = cell.as_ptr();
|
||||
let weaklist_ptr = unsafe { std::ptr::addr_of!((*base_ptr).contents.weakref) };
|
||||
unsafe { (weaklist_ptr as *const u8).offset_from(base_ptr as *const u8) }
|
||||
};
|
||||
#[cfg(not(addr_of))]
|
||||
let offset = {
|
||||
// No std::ptr::addr_of - need to take references to PyCell to measure offsets;
|
||||
// make a zero-initialised "fake" one so that referencing it is not UB.
|
||||
let mut cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
std::ptr::write_bytes(cell.as_mut_ptr(), 0, 1);
|
||||
}
|
||||
let cell = unsafe { cell.assume_init() };
|
||||
let weaklist_ptr = &cell.contents.weakref;
|
||||
// offset_from wasn't stabilised until 1.47, so we also have to work around
|
||||
// that...
|
||||
let offset = (weaklist_ptr as *const _ as usize) - (&cell as *const _ as usize);
|
||||
// This isn't a valid cell, so ensure no Drop code runs etc.
|
||||
std::mem::forget(cell);
|
||||
offset
|
||||
};
|
||||
// Py_ssize_t may not be equal to isize on all platforms
|
||||
#[allow(clippy::useless_conversion)]
|
||||
Some(offset.try_into().expect("offset should fit in Py_ssize_t"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: PyClass> PyNativeType for PyCell<T> {}
|
||||
|
||||
impl<T: PyClass> PyCell<T> {
|
||||
|
@ -502,6 +424,72 @@ impl<T: PyClass> PyCell<T> {
|
|||
fn get_ptr(&self) -> *mut T {
|
||||
self.contents.value.get()
|
||||
}
|
||||
|
||||
/// Gets the offset of the dictionary from the start of the struct in bytes.
|
||||
pub(crate) fn dict_offset() -> ffi::Py_ssize_t {
|
||||
use std::convert::TryInto;
|
||||
#[cfg(addr_of)]
|
||||
let offset = {
|
||||
// With std::ptr::addr_of - can measure offset using uninit memory without UB.
|
||||
let cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
let base_ptr = cell.as_ptr();
|
||||
let dict_ptr = unsafe { std::ptr::addr_of!((*base_ptr).contents.dict) };
|
||||
unsafe { (dict_ptr as *const u8).offset_from(base_ptr as *const u8) }
|
||||
};
|
||||
#[cfg(not(addr_of))]
|
||||
let offset = {
|
||||
// No std::ptr::addr_of - need to take references to PyCell to measure offsets;
|
||||
// make a zero-initialised "fake" one so that referencing it is not UB.
|
||||
let mut cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
std::ptr::write_bytes(cell.as_mut_ptr(), 0, 1);
|
||||
}
|
||||
let cell = unsafe { cell.assume_init() };
|
||||
let dict_ptr = &cell.contents.dict;
|
||||
// offset_from wasn't stabilised until 1.47, so we also have to work around
|
||||
// that...
|
||||
let offset = (dict_ptr as *const _ as usize) - (&cell as *const _ as usize);
|
||||
// This isn't a valid cell, so ensure no Drop code runs etc.
|
||||
std::mem::forget(cell);
|
||||
offset
|
||||
};
|
||||
// Py_ssize_t may not be equal to isize on all platforms
|
||||
#[allow(clippy::useless_conversion)]
|
||||
offset.try_into().expect("offset should fit in Py_ssize_t")
|
||||
}
|
||||
|
||||
/// Gets the offset of the weakref list from the start of the struct in bytes.
|
||||
pub(crate) fn weaklist_offset() -> ffi::Py_ssize_t {
|
||||
use std::convert::TryInto;
|
||||
#[cfg(addr_of)]
|
||||
let offset = {
|
||||
// With std::ptr::addr_of - can measure offset using uninit memory without UB.
|
||||
let cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
let base_ptr = cell.as_ptr();
|
||||
let weaklist_ptr = unsafe { std::ptr::addr_of!((*base_ptr).contents.weakref) };
|
||||
unsafe { (weaklist_ptr as *const u8).offset_from(base_ptr as *const u8) }
|
||||
};
|
||||
#[cfg(not(addr_of))]
|
||||
let offset = {
|
||||
// No std::ptr::addr_of - need to take references to PyCell to measure offsets;
|
||||
// make a zero-initialised "fake" one so that referencing it is not UB.
|
||||
let mut cell = std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
std::ptr::write_bytes(cell.as_mut_ptr(), 0, 1);
|
||||
}
|
||||
let cell = unsafe { cell.assume_init() };
|
||||
let weaklist_ptr = &cell.contents.weakref;
|
||||
// offset_from wasn't stabilised until 1.47, so we also have to work around
|
||||
// that...
|
||||
let offset = (weaklist_ptr as *const _ as usize) - (&cell as *const _ as usize);
|
||||
// This isn't a valid cell, so ensure no Drop code runs etc.
|
||||
std::mem::forget(cell);
|
||||
offset
|
||||
};
|
||||
// Py_ssize_t may not be equal to isize on all platforms
|
||||
#[allow(clippy::useless_conversion)]
|
||||
offset.try_into().expect("offset should fit in Py_ssize_t")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: PyClass> PyLayout<T> for PyCell<T> {}
|
||||
|
|
116
src/pyclass.rs
116
src/pyclass.rs
|
@ -1,8 +1,8 @@
|
|||
//! `PyClass` and related traits.
|
||||
use crate::{
|
||||
class::impl_::{fallback_new, tp_dealloc, PyClassImpl, PyBufferProcs},
|
||||
class::impl_::{fallback_new, tp_dealloc, PyBufferProcs, PyClassImpl},
|
||||
ffi,
|
||||
pyclass_slots::{PyClassDict, PyClassWeakRef},
|
||||
impl_::pyclass::{PyClassDict, PyClassWeakRef},
|
||||
PyCell, PyErr, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
||||
};
|
||||
use std::{
|
||||
|
@ -33,36 +33,37 @@ fn into_raw<T>(vec: Vec<T>) -> *mut c_void {
|
|||
Box::into_raw(vec.into_boxed_slice()) as _
|
||||
}
|
||||
|
||||
pub(crate) fn create_type_object<T>(
|
||||
py: Python,
|
||||
) -> *mut ffi::PyTypeObject
|
||||
pub(crate) fn create_type_object<T>(py: Python) -> *mut ffi::PyTypeObject
|
||||
where
|
||||
T: PyClass,
|
||||
{
|
||||
match unsafe { create_type_object_impl(
|
||||
py,
|
||||
T::DOC,
|
||||
T::MODULE,
|
||||
T::NAME,
|
||||
T::BaseType::type_object_raw(py),
|
||||
std::mem::size_of::<T::Layout>(),
|
||||
T::get_new(),
|
||||
tp_dealloc::<T>,
|
||||
T::get_alloc(),
|
||||
T::get_free(),
|
||||
PyCell::<T>::dict_offset(),
|
||||
PyCell::<T>::weakref_offset(),
|
||||
&T::for_each_method_def,
|
||||
&T::for_each_proto_slot,
|
||||
T::IS_GC,
|
||||
T::IS_BASETYPE,
|
||||
T::get_buffer(),
|
||||
) } {
|
||||
match unsafe {
|
||||
create_type_object_impl(
|
||||
py,
|
||||
T::DOC,
|
||||
T::MODULE,
|
||||
T::NAME,
|
||||
T::BaseType::type_object_raw(py),
|
||||
std::mem::size_of::<T::Layout>(),
|
||||
T::get_new(),
|
||||
tp_dealloc::<T>,
|
||||
T::get_alloc(),
|
||||
T::get_free(),
|
||||
T::dict_offset(),
|
||||
T::weaklist_offset(),
|
||||
&T::for_each_method_def,
|
||||
&T::for_each_proto_slot,
|
||||
T::IS_GC,
|
||||
T::IS_BASETYPE,
|
||||
T::get_buffer(),
|
||||
)
|
||||
} {
|
||||
Ok(type_object) => type_object,
|
||||
Err(e) => type_object_creation_failed(py, e, T::NAME),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
unsafe fn create_type_object_impl(
|
||||
py: Python,
|
||||
tp_doc: &str,
|
||||
|
@ -75,7 +76,7 @@ unsafe fn create_type_object_impl(
|
|||
tp_alloc: Option<ffi::allocfunc>,
|
||||
tp_free: Option<ffi::freefunc>,
|
||||
dict_offset: Option<ffi::Py_ssize_t>,
|
||||
weakref_offset: Option<ffi::Py_ssize_t>,
|
||||
weaklist_offset: Option<ffi::Py_ssize_t>,
|
||||
for_each_method_def: &dyn Fn(&mut dyn FnMut(&[PyMethodDefType])),
|
||||
for_each_proto_slot: &dyn Fn(&mut dyn FnMut(&[ffi::PyType_Slot])),
|
||||
is_gc: bool,
|
||||
|
@ -88,11 +89,7 @@ unsafe fn create_type_object_impl(
|
|||
slots.push(ffi::PyType_Slot { slot, pfunc });
|
||||
}
|
||||
|
||||
push_slot(
|
||||
&mut slots,
|
||||
ffi::Py_tp_base,
|
||||
base_type_object as _,
|
||||
);
|
||||
push_slot(&mut slots, ffi::Py_tp_base, base_type_object as _);
|
||||
if let Some(doc) = py_class_doc(tp_doc) {
|
||||
push_slot(&mut slots, ffi::Py_tp_doc, doc as _);
|
||||
}
|
||||
|
@ -113,7 +110,7 @@ unsafe fn create_type_object_impl(
|
|||
|
||||
#[cfg(Py_3_9)]
|
||||
{
|
||||
let members = py_class_members(dict_offset, weakref_offset);
|
||||
let members = py_class_members(dict_offset, weaklist_offset);
|
||||
if !members.is_empty() {
|
||||
push_slot(&mut slots, ffi::Py_tp_members, into_raw(members))
|
||||
}
|
||||
|
@ -153,7 +150,13 @@ unsafe fn create_type_object_impl(
|
|||
if type_object.is_null() {
|
||||
Err(PyErr::fetch(py))
|
||||
} else {
|
||||
tp_init_additional(type_object as _, tp_doc, buffer_procs, dict_offset, weakref_offset);
|
||||
tp_init_additional(
|
||||
type_object as _,
|
||||
tp_doc,
|
||||
buffer_procs,
|
||||
dict_offset,
|
||||
weaklist_offset,
|
||||
);
|
||||
Ok(type_object as _)
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +169,13 @@ fn type_object_creation_failed(py: Python, e: PyErr, name: &'static str) -> ! {
|
|||
|
||||
/// Additional type initializations necessary before Python 3.10
|
||||
#[cfg(all(not(Py_LIMITED_API), not(Py_3_10)))]
|
||||
fn tp_init_additional(type_object: *mut ffi::PyTypeObject, tp_doc: &str, buffer_procs: Option<&PyBufferProcs>, dict_offset: Option<ffi::Py_ssize_t>, weakref_offset: Option<ffi::Py_ssize_t>) {
|
||||
fn tp_init_additional(
|
||||
type_object: *mut ffi::PyTypeObject,
|
||||
_tp_doc: &str,
|
||||
_buffer_procs: Option<&PyBufferProcs>,
|
||||
_dict_offset: Option<ffi::Py_ssize_t>,
|
||||
_weaklist_offset: Option<ffi::Py_ssize_t>,
|
||||
) {
|
||||
// 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.
|
||||
|
@ -174,53 +183,54 @@ fn tp_init_additional(type_object: *mut ffi::PyTypeObject, tp_doc: &str, buffer_
|
|||
// Running this causes PyPy to segfault.
|
||||
#[cfg(all(not(PyPy), not(Py_3_10)))]
|
||||
{
|
||||
if tp_doc != "\0" {
|
||||
if _tp_doc != "\0" {
|
||||
unsafe {
|
||||
// Until CPython 3.10, tp_doc was treated specially for
|
||||
// heap-types, and it removed the text_signature value from it.
|
||||
// We go in after the fact and replace tp_doc with something
|
||||
// that _does_ include the text_signature value!
|
||||
ffi::PyObject_Free((*type_object).tp_doc as _);
|
||||
let data = ffi::PyObject_Malloc(tp_doc.len());
|
||||
data.copy_from(tp_doc.as_ptr() as _, tp_doc.len());
|
||||
let data = ffi::PyObject_Malloc(_tp_doc.len());
|
||||
data.copy_from(_tp_doc.as_ptr() as _, _tp_doc.len());
|
||||
(*type_object).tp_doc = data as _;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setting buffer protocols via slots doesn't work until Python 3.9, so on older versions we
|
||||
// must manually fixup the type object.
|
||||
// Setting buffer protocols, tp_dictoffset and tp_weaklistoffset via slots doesn't work until
|
||||
// Python 3.9, so on older versions we must manually fixup the type object.
|
||||
#[cfg(not(Py_3_9))]
|
||||
{
|
||||
if let Some(buffer) = buffer_procs {
|
||||
if let Some(buffer) = _buffer_procs {
|
||||
unsafe {
|
||||
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer.bf_getbuffer;
|
||||
(*(*type_object).tp_as_buffer).bf_releasebuffer = buffer.bf_releasebuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setting tp_dictoffset and tp_weaklistoffset via slots doesn't work until Python 3.9, so on
|
||||
// older versions again we must fixup the type object.
|
||||
#[cfg(not(Py_3_9))]
|
||||
{
|
||||
// __dict__ support
|
||||
if let Some(dict_offset) = dict_offset {
|
||||
if let Some(dict_offset) = _dict_offset {
|
||||
unsafe {
|
||||
(*type_object).tp_dictoffset = dict_offset;
|
||||
}
|
||||
}
|
||||
// weakref support
|
||||
if let Some(weakref_offset) = weakref_offset {
|
||||
|
||||
if let Some(weaklist_offset) = _weaklist_offset {
|
||||
unsafe {
|
||||
(*type_object).tp_weaklistoffset = weakref_offset;
|
||||
(*type_object).tp_weaklistoffset = weaklist_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(Py_LIMITED_API, Py_3_10))]
|
||||
fn tp_init_additional(_type_object: *mut ffi::PyTypeObject, tp_doc: &str, buffer_procs: Option<&PyBufferProcs>, dict_offset: Option<ffi::Py_ssize_t>, weakref_offset: Option<ffi::Py_ssize_t>) {}
|
||||
fn tp_init_additional(
|
||||
_type_object: *mut ffi::PyTypeObject,
|
||||
_tp_doc: &str,
|
||||
_buffer_procs: Option<&PyBufferProcs>,
|
||||
_dict_offset: Option<ffi::Py_ssize_t>,
|
||||
_weaklist_offset: Option<ffi::Py_ssize_t>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn py_class_doc(class_doc: &str) -> Option<*mut c_char> {
|
||||
match class_doc {
|
||||
|
@ -293,7 +303,7 @@ fn py_class_method_defs(
|
|||
#[cfg(Py_3_9)]
|
||||
fn py_class_members(
|
||||
dict_offset: Option<isize>,
|
||||
weakref_offset: Option<isize>,
|
||||
weaklist_offset: Option<isize>,
|
||||
) -> Vec<ffi::structmember::PyMemberDef> {
|
||||
#[inline(always)]
|
||||
fn offset_def(name: &'static str, offset: ffi::Py_ssize_t) -> ffi::structmember::PyMemberDef {
|
||||
|
@ -314,8 +324,8 @@ fn py_class_members(
|
|||
}
|
||||
|
||||
// weakref support
|
||||
if let Some(weakref_offset) = weakref_offset {
|
||||
members.push(offset_def("__weaklistoffset__\0", weakref_offset));
|
||||
if let Some(weaklist_offset) = weaklist_offset {
|
||||
members.push(offset_def("__weaklistoffset__\0", weaklist_offset));
|
||||
}
|
||||
|
||||
if !members.is_empty() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Contains initialization utilities for `#[pyclass]`.
|
||||
use crate::class::impl_::PyClassThreadChecker;
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::impl_::pyclass::{PyClassDict, PyClassWeakRef};
|
||||
use crate::{callback::IntoPyCallbackOutput, class::impl_::PyClassBaseType};
|
||||
use crate::{ffi, PyCell, PyClass, PyErr, PyResult, Python};
|
||||
use crate::{
|
||||
|
|
|
@ -344,7 +344,6 @@ fn test_tuple_struct_class() {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
#[pyclass(dict, subclass)]
|
||||
struct DunderDictSupport {}
|
||||
|
||||
|
@ -419,8 +418,6 @@ fn weakref_dunder_dict_support() {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[pyclass(weakref, subclass)]
|
||||
struct WeakRefSupport {}
|
||||
|
||||
|
|
|
@ -9,10 +9,9 @@ note: required by a bound in `PyClassBaseType`
|
|||
--> src/class/impl_.rs
|
||||
|
|
||||
| / pub trait PyClassBaseType: Sized {
|
||||
| | type Dict;
|
||||
| | type WeakRef;
|
||||
| | type LayoutAsBase: PyCellLayout<Self>;
|
||||
... |
|
||||
| | type BaseNativeType;
|
||||
| | type ThreadChecker: PyClassThreadChecker<Self>;
|
||||
| | type Initializer: PyObjectInit<Self>;
|
||||
| | }
|
||||
| |_^ required by this bound in `PyClassBaseType`
|
||||
|
|
Loading…
Reference in New Issue