Merge pull request #3335 from davidhewitt/3.12-ffi-immortal

update object.h definitions for Python 3.12
This commit is contained in:
David Hewitt 2023-07-30 15:27:10 +00:00 committed by GitHub
commit 6c25b7355e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 401 additions and 157 deletions

View File

@ -0,0 +1 @@
Update FFI definitions of `object.h` for Python 3.12 and up.

View File

@ -0,0 +1 @@
Fix reference counting of immortal objects on Python 3.12 betas.

View File

@ -1,4 +1,6 @@
use crate::object;
#[cfg(Py_3_8)]
use crate::vectorcallfunc;
use crate::{PyObject, Py_ssize_t};
use std::mem;
use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void};
@ -112,14 +114,6 @@ mod bufferinfo {
#[cfg(not(Py_3_11))]
pub use self::bufferinfo::*;
#[cfg(Py_3_8)]
pub type vectorcallfunc = unsafe extern "C" fn(
callable: *mut PyObject,
args: *const *mut PyObject,
nargsf: libc::size_t,
kwnames: *mut PyObject,
) -> *mut PyObject;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyNumberMethods {
@ -275,7 +269,7 @@ pub struct PyTypeObject {
pub tp_version_tag: c_uint,
pub tp_finalize: Option<object::destructor>,
#[cfg(Py_3_8)]
pub tp_vectorcall: Option<super::vectorcallfunc>,
pub tp_vectorcall: Option<vectorcallfunc>,
#[cfg(Py_3_12)]
pub tp_watched: c_char,
#[cfg(any(all(PyPy, Py_3_8, not(Py_3_10)), all(not(PyPy), Py_3_8, not(Py_3_9))))]

View File

@ -259,8 +259,6 @@ macro_rules! opaque_struct {
pub use self::abstract_::*;
pub use self::bltinmodule::*;
pub use self::boolobject::*;
#[cfg(Py_3_11)]
pub use self::buffer::*;
pub use self::bytearrayobject::*;
pub use self::bytesobject::*;
pub use self::ceval::*;
@ -293,6 +291,8 @@ pub use self::objimpl::*;
pub use self::osmodule::*;
#[cfg(not(any(PyPy, Py_LIMITED_API, Py_3_10)))]
pub use self::pyarena::*;
#[cfg(Py_3_11)]
pub use self::pybuffer::*;
pub use self::pycapsule::*;
pub use self::pyerrors::*;
pub use self::pyframe::*;
@ -320,8 +320,6 @@ mod abstract_;
// skipped ast.h
mod bltinmodule;
mod boolobject;
#[cfg(Py_3_11)]
mod buffer;
mod bytearrayobject;
mod bytesobject;
// skipped cellobject.h
@ -372,8 +370,9 @@ mod osmodule;
// skipped py_curses.h
#[cfg(not(any(PyPy, Py_LIMITED_API, Py_3_10)))]
mod pyarena;
#[cfg(Py_3_11)]
mod pybuffer;
mod pycapsule;
// skipped pydecimal.h
// skipped pydtrace.h
mod pyerrors;
// skipped pyexpat.h
@ -387,6 +386,7 @@ mod pylifecycle;
mod pymem;
mod pyport;
mod pystate;
// skipped pystats.h
mod pythonrun;
// skipped pystrhex.h
// skipped pystrcmp.h

View File

@ -1,5 +1,3 @@
// FFI note: this file changed a lot between 3.6 and 3.10.
// Some missing definitions may not be marked "skipped".
use crate::pyport::{Py_hash_t, Py_ssize_t};
use std::mem;
use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void};
@ -14,11 +12,24 @@ pub use crate::cpython::object::PyTypeObject;
// _PyObject_HEAD_EXTRA: conditionally defined in PyObject_HEAD_INIT
// _PyObject_EXTRA_INIT: conditionally defined in PyObject_HEAD_INIT
#[cfg(Py_3_12)]
pub const _Py_IMMORTAL_REFCNT: Py_ssize_t = {
if cfg!(target_pointer_width = "64") {
c_uint::MAX as Py_ssize_t
} else {
// for 32-bit systems, use the lower 30 bits (see comment in CPython's object.h)
(c_uint::MAX >> 2) as Py_ssize_t
}
};
pub const PyObject_HEAD_INIT: PyObject = PyObject {
#[cfg(py_sys_config = "Py_TRACE_REFS")]
_ob_next: std::ptr::null_mut(),
#[cfg(py_sys_config = "Py_TRACE_REFS")]
_ob_prev: std::ptr::null_mut(),
#[cfg(Py_3_12)]
ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 },
#[cfg(not(Py_3_12))]
ob_refcnt: 1,
#[cfg(PyPy)]
ob_pypy_link: 0,
@ -28,6 +39,27 @@ pub const PyObject_HEAD_INIT: PyObject = PyObject {
// skipped PyObject_VAR_HEAD
// skipped Py_INVALID_SIZE
#[repr(C)]
#[derive(Copy, Clone)]
#[cfg(Py_3_12)]
/// This union is anonymous in CPython, so the name was given by PyO3 because
/// Rust unions need a name.
pub union PyObjectObRefcnt {
pub ob_refcnt: Py_ssize_t,
#[cfg(target_pointer_width = "64")]
pub ob_refcnt_split: [crate::PY_UINT32_T; 2],
}
#[cfg(Py_3_12)]
impl std::fmt::Debug for PyObjectObRefcnt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", unsafe { self.ob_refcnt })
}
}
#[cfg(not(Py_3_12))]
pub type PyObjectObRefcnt = Py_ssize_t;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct PyObject {
@ -35,14 +67,13 @@ pub struct PyObject {
pub _ob_next: *mut PyObject,
#[cfg(py_sys_config = "Py_TRACE_REFS")]
pub _ob_prev: *mut PyObject,
pub ob_refcnt: Py_ssize_t,
pub ob_refcnt: PyObjectObRefcnt,
#[cfg(PyPy)]
pub ob_pypy_link: Py_ssize_t,
pub ob_type: *mut PyTypeObject,
}
// skipped _PyObject_CAST
// skipped _PyObject_CAST_CONST
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@ -52,18 +83,21 @@ pub struct PyVarObject {
}
// skipped _PyVarObject_CAST
// skipped _PyVarObject_CAST_CONST
#[inline]
pub unsafe fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int {
(x == y).into()
}
// skipped _Py_REFCNT: defined in Py_REFCNT
#[inline]
#[cfg(Py_3_12)]
pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t {
(*ob).ob_refcnt.ob_refcnt
}
#[inline]
#[cfg(not(Py_3_12))]
pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t {
assert!(!ob.is_null());
(*ob).ob_refcnt
}
@ -72,9 +106,14 @@ pub unsafe fn Py_TYPE(ob: *mut PyObject) -> *mut PyTypeObject {
(*ob).ob_type
}
// PyLong_Type defined in longobject.rs
// PyBool_Type defined in boolobject.rs
#[inline]
pub unsafe fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t {
(*(ob as *mut PyVarObject)).ob_size
debug_assert_ne!((*ob).ob_type, std::ptr::addr_of_mut!(crate::PyLong_Type));
debug_assert_ne!((*ob).ob_type, std::ptr::addr_of_mut!(crate::PyBool_Type));
(*ob.cast::<PyVarObject>()).ob_size
}
#[inline]
@ -82,6 +121,18 @@ pub unsafe fn Py_IS_TYPE(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int {
(Py_TYPE(ob) == tp) as c_int
}
#[inline(always)]
#[cfg(all(Py_3_12, target_pointer_width = "64"))]
pub unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int {
(((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int
}
#[inline(always)]
#[cfg(all(Py_3_12, target_pointer_width = "32"))]
pub unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int {
((*op).ob_refcnt.ob_refcnt == _Py_IMMORTAL_REFCNT) as c_int
}
// skipped _Py_SET_REFCNT
// skipped Py_SET_REFCNT
// skipped _Py_SET_TYPE
@ -89,82 +140,51 @@ pub unsafe fn Py_IS_TYPE(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int {
// skipped _Py_SET_SIZE
// skipped Py_SET_SIZE
pub type unaryfunc = unsafe extern "C" fn(arg1: *mut PyObject) -> *mut PyObject;
pub type binaryfunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject;
pub type ternaryfunc = unsafe extern "C" fn(
arg1: *mut PyObject,
arg2: *mut PyObject,
arg3: *mut PyObject,
) -> *mut PyObject;
pub type inquiry = unsafe extern "C" fn(arg1: *mut PyObject) -> c_int;
pub type lenfunc = unsafe extern "C" fn(arg1: *mut PyObject) -> Py_ssize_t;
pub type ssizeargfunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: Py_ssize_t) -> *mut PyObject;
pub type unaryfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
pub type binaryfunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject;
pub type ternaryfunc =
unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> *mut PyObject;
pub type inquiry = unsafe extern "C" fn(*mut PyObject) -> c_int;
pub type lenfunc = unsafe extern "C" fn(*mut PyObject) -> Py_ssize_t;
pub type ssizeargfunc = unsafe extern "C" fn(*mut PyObject, Py_ssize_t) -> *mut PyObject;
pub type ssizessizeargfunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: Py_ssize_t, arg3: Py_ssize_t) -> *mut PyObject;
unsafe extern "C" fn(*mut PyObject, Py_ssize_t, Py_ssize_t) -> *mut PyObject;
pub type ssizeobjargproc = unsafe extern "C" fn(*mut PyObject, Py_ssize_t, *mut PyObject) -> c_int;
pub type ssizessizeobjargproc =
unsafe extern "C" fn(*mut PyObject, Py_ssize_t, Py_ssize_t, arg4: *mut PyObject) -> c_int;
pub type objobjargproc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
pub type ssizeobjargproc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: Py_ssize_t, arg3: *mut PyObject) -> c_int;
pub type ssizessizeobjargproc = unsafe extern "C" fn(
arg1: *mut PyObject,
arg2: Py_ssize_t,
arg3: Py_ssize_t,
arg4: *mut PyObject,
) -> c_int;
pub type objobjargproc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> c_int;
pub type objobjproc = unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int;
pub type objobjproc = unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> c_int;
pub type visitproc = unsafe extern "C" fn(object: *mut PyObject, arg: *mut c_void) -> c_int;
pub type traverseproc =
unsafe extern "C" fn(slf: *mut PyObject, visit: visitproc, arg: *mut c_void) -> c_int;
pub type freefunc = unsafe extern "C" fn(arg1: *mut c_void);
pub type destructor = unsafe extern "C" fn(arg1: *mut PyObject);
pub type getattrfunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut c_char) -> *mut PyObject;
pub type getattrofunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject;
pub type setattrfunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut c_char, arg3: *mut PyObject) -> c_int;
pub type setattrofunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> c_int;
pub type reprfunc = unsafe extern "C" fn(arg1: *mut PyObject) -> *mut PyObject;
pub type hashfunc = unsafe extern "C" fn(arg1: *mut PyObject) -> Py_hash_t;
pub type richcmpfunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject, arg3: c_int) -> *mut PyObject;
pub type getiterfunc = unsafe extern "C" fn(arg1: *mut PyObject) -> *mut PyObject;
pub type iternextfunc = unsafe extern "C" fn(arg1: *mut PyObject) -> *mut PyObject;
pub type descrgetfunc = unsafe extern "C" fn(
arg1: *mut PyObject,
arg2: *mut PyObject,
arg3: *mut PyObject,
pub type freefunc = unsafe extern "C" fn(*mut c_void);
pub type destructor = unsafe extern "C" fn(*mut PyObject);
pub type getattrfunc = unsafe extern "C" fn(*mut PyObject, *mut c_char) -> *mut PyObject;
pub type getattrofunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject;
pub type setattrfunc = unsafe extern "C" fn(*mut PyObject, *mut c_char, *mut PyObject) -> c_int;
pub type setattrofunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
pub type reprfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
pub type hashfunc = unsafe extern "C" fn(*mut PyObject) -> Py_hash_t;
pub type richcmpfunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, c_int) -> *mut PyObject;
pub type getiterfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
pub type iternextfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
pub type descrgetfunc =
unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> *mut PyObject;
pub type descrsetfunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
pub type initproc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
pub type newfunc =
unsafe extern "C" fn(*mut PyTypeObject, *mut PyObject, *mut PyObject) -> *mut PyObject;
pub type allocfunc = unsafe extern "C" fn(*mut PyTypeObject, Py_ssize_t) -> *mut PyObject;
#[cfg(Py_3_8)]
pub type vectorcallfunc = unsafe extern "C" fn(
callable: *mut PyObject,
args: *const *mut PyObject,
nargsf: libc::size_t,
kwnames: *mut PyObject,
) -> *mut PyObject;
pub type descrsetfunc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> c_int;
pub type initproc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject) -> c_int;
pub type newfunc = unsafe extern "C" fn(
arg1: *mut PyTypeObject,
arg2: *mut PyObject,
arg3: *mut PyObject,
) -> *mut PyObject;
pub type allocfunc =
unsafe extern "C" fn(arg1: *mut PyTypeObject, arg2: Py_ssize_t) -> *mut PyObject;
#[cfg(Py_3_11)]
pub type getbufferproc =
unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut crate::Py_buffer, arg3: c_int) -> c_int;
#[cfg(Py_3_11)]
pub type releasebufferproc = unsafe extern "C" fn(arg1: *mut PyObject, arg2: *mut crate::Py_buffer);
#[repr(C)]
#[derive(Copy, Clone)]
@ -220,9 +240,32 @@ extern "C" {
#[cfg(any(Py_3_10, all(Py_3_9, not(Py_LIMITED_API))))]
#[cfg_attr(PyPy, link_name = "PyPyType_GetModuleState")]
pub fn PyType_GetModuleState(arg1: *mut PyTypeObject) -> *mut c_void;
}
extern "C" {
#[cfg(Py_3_11)]
#[cfg_attr(PyPy, link_name = "PyPyType_GetName")]
pub fn PyType_GetName(arg1: *mut PyTypeObject) -> *mut PyObject;
#[cfg(Py_3_11)]
#[cfg_attr(PyPy, link_name = "PyPyType_GetQualName")]
pub fn PyType_GetQualName(arg1: *mut PyTypeObject) -> *mut PyObject;
#[cfg(Py_3_12)]
#[cfg_attr(PyPy, link_name = "PyPyType_FromMetaclass")]
pub fn PyType_FromMetaclass(
metaclass: *mut PyTypeObject,
module: *mut PyObject,
spec: *mut PyType_Spec,
bases: *mut PyObject,
) -> *mut PyObject;
#[cfg(Py_3_12)]
#[cfg_attr(PyPy, link_name = "PyPyObject_GetTypeData")]
pub fn PyObject_GetTypeData(obj: *mut PyObject, cls: *mut PyTypeObject) -> *mut c_void;
#[cfg(Py_3_12)]
#[cfg_attr(PyPy, link_name = "PyPyObject_GetTypeDataSize")]
pub fn PyObject_GetTypeDataSize(cls: *mut PyTypeObject) -> Py_ssize_t;
#[cfg_attr(PyPy, link_name = "PyPyType_IsSubtype")]
pub fn PyType_IsSubtype(a: *mut PyTypeObject, b: *mut PyTypeObject) -> c_int;
}
@ -246,9 +289,7 @@ extern "C" {
extern "C" {
pub fn PyType_GetFlags(arg1: *mut PyTypeObject) -> c_ulong;
}
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPyType_Ready")]
pub fn PyType_Ready(t: *mut PyTypeObject) -> c_int;
#[cfg_attr(PyPy, link_name = "PyPyType_GenericAlloc")]
@ -337,6 +378,15 @@ extern "C" {
// Flag bits for printing:
pub const Py_PRINT_RAW: c_int = 1; // No string quotes etc.
#[cfg(all(Py_3_12, not(Py_LIMITED_API)))]
pub const _Py_TPFLAGS_STATIC_BUILTIN: c_ulong = 1 << 1;
#[cfg(all(Py_3_12, not(Py_LIMITED_API)))]
pub const Py_TPFLAGS_MANAGED_WEAKREF: c_ulong = 1 << 3;
#[cfg(all(Py_3_11, not(Py_LIMITED_API)))]
pub const Py_TPFLAGS_MANAGED_DICT: c_ulong = 1 << 4;
#[cfg(all(Py_3_10, not(Py_LIMITED_API)))]
pub const Py_TPFLAGS_SEQUENCE: c_ulong = 1 << 5;
@ -356,7 +406,7 @@ pub const Py_TPFLAGS_HEAPTYPE: c_ulong = 1 << 9;
pub const Py_TPFLAGS_BASETYPE: c_ulong = 1 << 10;
/// Set if the type implements the vectorcall protocol (PEP 590)
#[cfg(all(Py_3_8, not(Py_LIMITED_API)))]
#[cfg(any(Py_3_12, all(Py_3_8, not(Py_LIMITED_API))))]
pub const Py_TPFLAGS_HAVE_VECTORCALL: c_ulong = 1 << 11;
// skipped non-limited _Py_TPFLAGS_HAVE_VECTORCALL
@ -374,15 +424,14 @@ const Py_TPFLAGS_HAVE_STACKLESS_EXTENSION: c_ulong = 0;
#[cfg(Py_3_8)]
pub const Py_TPFLAGS_METHOD_DESCRIPTOR: c_ulong = 1 << 17;
/// This flag does nothing in Python 3.10+
pub const Py_TPFLAGS_HAVE_VERSION_TAG: c_ulong = 1 << 18;
pub const Py_TPFLAGS_VALID_VERSION_TAG: c_ulong = 1 << 19;
/* Type is abstract and cannot be instantiated */
pub const Py_TPFLAGS_IS_ABSTRACT: c_ulong = 1 << 20;
// skipped non-limited / 3.10 Py_TPFLAGS_HAVE_AM_SEND
#[cfg(Py_3_12)]
pub const Py_TPFLAGS_ITEMS_AT_END: c_ulong = 1 << 23;
/* These flags are used to determine if a type is a subclass. */
pub const Py_TPFLAGS_LONG_SUBCLASS: c_ulong = 1 << 24;
@ -394,37 +443,161 @@ pub const Py_TPFLAGS_DICT_SUBCLASS: c_ulong = 1 << 29;
pub const Py_TPFLAGS_BASE_EXC_SUBCLASS: c_ulong = 1 << 30;
pub const Py_TPFLAGS_TYPE_SUBCLASS: c_ulong = 1 << 31;
pub const Py_TPFLAGS_DEFAULT: c_ulong =
Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | Py_TPFLAGS_HAVE_VERSION_TAG;
pub const Py_TPFLAGS_DEFAULT: c_ulong = if cfg!(Py_3_10) {
Py_TPFLAGS_HAVE_STACKLESS_EXTENSION
} else {
Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | Py_TPFLAGS_HAVE_VERSION_TAG
};
pub const Py_TPFLAGS_HAVE_FINALIZE: c_ulong = 1;
pub const Py_TPFLAGS_HAVE_VERSION_TAG: c_ulong = 1 << 18;
// skipped _Py_RefTotal
// skipped _Py_NegativeRefCount
#[cfg(all(py_sys_config = "Py_REF_DEBUG", not(Py_LIMITED_API)))]
extern "C" {
pub fn _Py_NegativeRefCount(filename: *const c_char, lineno: c_int, op: *mut PyObject);
#[cfg(Py_3_12)]
#[link_name = "_Py_IncRefTotal_DO_NOT_USE_THIS"]
fn _Py_INC_REFTOTAL();
#[cfg(Py_3_12)]
#[link_name = "_Py_DecRefTotal_DO_NOT_USE_THIS"]
fn _Py_DEC_REFTOTAL();
}
extern "C" {
#[cfg_attr(PyPy, link_name = "_PyPy_Dealloc")]
pub fn _Py_Dealloc(arg1: *mut PyObject);
#[cfg_attr(PyPy, link_name = "PyPy_IncRef")]
pub fn Py_IncRef(o: *mut PyObject);
#[cfg_attr(PyPy, link_name = "PyPy_DecRef")]
pub fn Py_DecRef(o: *mut PyObject);
#[cfg(Py_3_10)]
#[cfg_attr(PyPy, link_name = "_PyPy_IncRef")]
pub fn _Py_IncRef(o: *mut PyObject);
#[cfg(Py_3_10)]
#[cfg_attr(PyPy, link_name = "_PyPy_DecRef")]
pub fn _Py_DecRef(o: *mut PyObject);
}
// Reference counting macros.
#[inline]
#[inline(always)]
pub unsafe fn Py_INCREF(op: *mut PyObject) {
if cfg!(py_sys_config = "Py_REF_DEBUG") {
Py_IncRef(op)
} else {
(*op).ob_refcnt += 1
#[cfg(any(
all(Py_LIMITED_API, Py_3_12),
all(
py_sys_config = "Py_REF_DEBUG",
Py_3_10,
not(all(Py_3_12, not(Py_LIMITED_API)))
)
))]
{
return _Py_IncRef(op);
}
#[cfg(all(py_sys_config = "Py_REF_DEBUG", not(Py_3_10)))]
{
return Py_IncRef(op);
}
#[cfg(any(
not(Py_LIMITED_API),
all(Py_LIMITED_API, not(Py_3_12)),
all(py_sys_config = "Py_REF_DEBUG", Py_3_12, not(Py_LIMITED_API))
))]
{
#[cfg(all(Py_3_12, target_pointer_width = "64"))]
{
let cur_refcnt = (*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN];
let new_refcnt = cur_refcnt.wrapping_add(1);
if new_refcnt == 0 {
return;
}
(*op).ob_refcnt.ob_refcnt_split[crate::PY_BIG_ENDIAN] = new_refcnt;
}
#[cfg(all(Py_3_12, target_pointer_width = "32"))]
{
if _Py_IsImmortal(op) != 0 {
return;
}
(*op).ob_refcnt.ob_refcnt += 1
}
#[cfg(not(Py_3_12))]
{
(*op).ob_refcnt += 1
}
// Skipped _Py_INCREF_STAT_INC - if anyone wants this, please file an issue
// or submit a PR supporting Py_STATS build option and pystats.h
#[cfg(all(py_sys_config = "Py_REF_DEBUG", Py_3_12))]
_Py_INC_REFTOTAL();
}
}
#[inline]
#[inline(always)]
#[cfg_attr(
all(py_sys_config = "Py_REF_DEBUG", Py_3_12, not(Py_LIMITED_API)),
track_caller
)]
pub unsafe fn Py_DECREF(op: *mut PyObject) {
if cfg!(py_sys_config = "Py_REF_DEBUG") {
Py_DecRef(op)
} else {
(*op).ob_refcnt -= 1;
if (*op).ob_refcnt == 0 {
_Py_Dealloc(op)
#[cfg(any(
all(Py_LIMITED_API, Py_3_12),
all(
py_sys_config = "Py_REF_DEBUG",
Py_3_10,
not(all(Py_3_12, not(Py_LIMITED_API)))
)
))]
{
return _Py_DecRef(op);
}
#[cfg(all(py_sys_config = "Py_REF_DEBUG", not(Py_3_10)))]
{
return Py_DecRef(op);
}
#[cfg(any(
not(Py_LIMITED_API),
all(Py_LIMITED_API, not(Py_3_12)),
all(py_sys_config = "Py_REF_DEBUG", Py_3_12, not(Py_LIMITED_API))
))]
{
#[cfg(Py_3_12)]
if _Py_IsImmortal(op) != 0 {
return;
}
// Skipped _Py_DECREF_STAT_INC - if anyone needs this, please file an issue
// or submit a PR supporting Py_STATS build option and pystats.h
#[cfg(all(py_sys_config = "Py_REF_DEBUG", Py_3_12))]
_Py_DEC_REFTOTAL();
#[cfg(Py_3_12)]
{
(*op).ob_refcnt.ob_refcnt -= 1;
#[cfg(py_sys_config = "Py_REF_DEBUG")]
if (*op).ob_refcnt.ob_refcnt < 0 {
let location = std::panic::Location::caller();
_Py_NegativeRefcount(location.file(), location.line(), op);
}
if (*op).ob_refcnt.ob_refcnt == 0 {
_Py_Dealloc(op);
}
}
#[cfg(not(Py_3_12))]
{
(*op).ob_refcnt -= 1;
if (*op).ob_refcnt == 0 {
_Py_Dealloc(op);
}
}
}
}
@ -453,14 +626,9 @@ pub unsafe fn Py_XDECREF(op: *mut PyObject) {
}
extern "C" {
#[cfg_attr(PyPy, link_name = "PyPy_IncRef")]
pub fn Py_IncRef(o: *mut PyObject);
#[cfg_attr(PyPy, link_name = "PyPy_DecRef")]
pub fn Py_DecRef(o: *mut PyObject);
#[cfg(Py_3_10)]
#[cfg(all(Py_3_10, Py_LIMITED_API))]
pub fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject;
#[cfg(Py_3_10)]
#[cfg(all(Py_3_10, Py_LIMITED_API))]
pub fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject;
}
@ -480,6 +648,18 @@ pub unsafe fn _Py_XNewRef(obj: *mut PyObject) -> *mut PyObject {
obj
}
#[cfg(all(Py_3_10, not(Py_LIMITED_API)))]
#[inline]
pub unsafe fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject {
_Py_NewRef(obj)
}
#[cfg(all(Py_3_10, not(Py_LIMITED_API)))]
#[inline]
pub unsafe fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject {
_Py_XNewRef(obj)
}
#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
#[cfg_attr(PyPy, link_name = "_PyPy_NoneStruct")]
@ -554,5 +734,5 @@ pub unsafe fn PyType_Check(op: *mut PyObject) -> c_int {
#[inline]
pub unsafe fn PyType_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == ptr::addr_of_mut!(PyType_Type)) as c_int
Py_IS_TYPE(op, ptr::addr_of_mut!(PyType_Type))
}

View File

@ -53,6 +53,9 @@ impl Py_buffer {
}
}
pub type getbufferproc = unsafe extern "C" fn(*mut PyObject, *mut crate::Py_buffer, c_int) -> c_int;
pub type releasebufferproc = unsafe extern "C" fn(*mut PyObject, *mut crate::Py_buffer);
/* Return 1 if the getbuffer function is available, otherwise return 0. */
extern "C" {
#[cfg(not(PyPy))]

View File

@ -1,3 +1,9 @@
pub type PY_UINT32_T = u32;
pub type PY_UINT64_T = u64;
pub type PY_INT32_T = i32;
pub type PY_INT64_T = i64;
pub type Py_uintptr_t = ::libc::uintptr_t;
pub type Py_intptr_t = ::libc::intptr_t;
pub type Py_ssize_t = ::libc::ssize_t;
@ -7,3 +13,13 @@ pub type Py_uhash_t = ::libc::size_t;
pub const PY_SSIZE_T_MIN: Py_ssize_t = std::isize::MIN as Py_ssize_t;
pub const PY_SSIZE_T_MAX: Py_ssize_t = std::isize::MAX as Py_ssize_t;
#[cfg(target_endian = "big")]
pub const PY_BIG_ENDIAN: usize = 1;
#[cfg(target_endian = "big")]
pub const PY_LITTLE_ENDIAN: usize = 0;
#[cfg(target_endian = "little")]
pub const PY_BIG_ENDIAN: usize = 0;
#[cfg(target_endian = "little")]
pub const PY_LITTLE_ENDIAN: usize = 1;

View File

@ -21,7 +21,7 @@
//!
//! [capi]: https://docs.python.org/3/c-api/index.html
#[cfg(all(not(Py_LIMITED_API), test))]
#[cfg(test)]
mod tests;
// reexport raw bindings exposed in pyo3_ffi

View File

@ -1,10 +1,15 @@
use crate::ffi::*;
use crate::{types::PyDict, AsPyPointer, IntoPy, Py, PyAny, Python};
use crate::{AsPyPointer, Python};
use crate::types::PyString;
#[cfg(not(Py_3_12))]
#[cfg(not(Py_LIMITED_API))]
use crate::{
types::{PyDict, PyString},
IntoPy, Py, PyAny,
};
#[cfg(not(any(Py_3_12, Py_LIMITED_API)))]
use libc::wchar_t;
#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons
#[test]
fn test_datetime_fromtimestamp() {
@ -25,6 +30,7 @@ fn test_datetime_fromtimestamp() {
})
}
#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons
#[test]
fn test_date_fromtimestamp() {
@ -45,6 +51,7 @@ fn test_date_fromtimestamp() {
})
}
#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons
#[test]
fn test_utc_timezone() {
@ -65,6 +72,7 @@ fn test_utc_timezone() {
}
#[test]
#[cfg(not(Py_LIMITED_API))]
#[cfg(feature = "macros")]
#[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons
fn test_timezone_from_offset() {
@ -82,6 +90,7 @@ fn test_timezone_from_offset() {
}
#[test]
#[cfg(not(Py_LIMITED_API))]
#[cfg(feature = "macros")]
#[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons
fn test_timezone_from_offset_and_name() {
@ -105,6 +114,7 @@ fn test_timezone_from_offset_and_name() {
}
#[test]
#[cfg(not(Py_LIMITED_API))]
fn ascii_object_bitfield() {
let ob_base: PyObject = unsafe { std::mem::zeroed() };
@ -152,6 +162,7 @@ fn ascii_object_bitfield() {
}
#[test]
#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(Py_3_10, allow(deprecated))]
fn ascii() {
Python::with_gil(|py| {
@ -193,6 +204,7 @@ fn ascii() {
}
#[test]
#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(Py_3_10, allow(deprecated))]
fn ucs4() {
Python::with_gil(|py| {
@ -236,6 +248,7 @@ fn ucs4() {
}
#[test]
#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons
#[cfg(not(PyPy))]
fn test_get_tzinfo() {
@ -276,3 +289,40 @@ fn test_get_tzinfo() {
);
})
}
#[test]
fn test_inc_dec_ref() {
Python::with_gil(|py| {
let obj = py.eval("object()", None, None).unwrap();
let ref_count = obj.get_refcnt();
let ptr = obj.as_ptr();
unsafe { Py_INCREF(ptr) };
assert_eq!(obj.get_refcnt(), ref_count + 1);
unsafe { Py_DECREF(ptr) };
assert_eq!(obj.get_refcnt(), ref_count);
})
}
#[test]
#[cfg(Py_3_12)]
fn test_inc_dec_ref_immortal() {
Python::with_gil(|py| {
let obj = py.None();
let ref_count = obj.get_refcnt(py);
let ptr = obj.as_ptr();
unsafe { Py_INCREF(ptr) };
assert_eq!(obj.get_refcnt(py), ref_count);
unsafe { Py_DECREF(ptr) };
assert_eq!(obj.get_refcnt(py), ref_count);
})
}

View File

@ -591,14 +591,14 @@ mod tests {
fn test_set_item_refcnt() {
Python::with_gil(|py| {
let cnt;
let obj = py.eval("object()", None, None).unwrap();
{
let _pool = unsafe { crate::GILPool::new() };
let none = py.None();
cnt = none.get_refcnt(py);
let _dict = [(10, none)].into_py_dict(py);
cnt = obj.get_refcnt();
let _dict = [(10, obj)].into_py_dict(py);
}
{
assert_eq!(cnt, py.None().get_refcnt(py));
assert_eq!(cnt, obj.get_refcnt());
}
});
}

View File

@ -155,31 +155,30 @@ mod tests {
#[test]
fn iter_item_refcnt() {
Python::with_gil(|py| {
let obj;
let none;
let count;
{
let obj = py.eval("object()", None, None).unwrap();
let list = {
let _pool = unsafe { GILPool::new() };
let l = PyList::empty(py);
none = py.None();
l.append(10).unwrap();
l.append(&none).unwrap();
count = none.get_refcnt(py);
obj = l.to_object(py);
}
let list = PyList::empty(py);
list.append(10).unwrap();
list.append(obj).unwrap();
count = obj.get_refcnt();
list.to_object(py)
};
{
let _pool = unsafe { GILPool::new() };
let inst = obj.as_ref(py);
let inst = list.as_ref(py);
let mut it = inst.iter().unwrap();
assert_eq!(
10_i32,
it.next().unwrap().unwrap().extract::<'_, i32>().unwrap()
);
assert!(it.next().unwrap().unwrap().is_none());
assert!(it.next().unwrap().unwrap().is(obj));
assert!(it.next().is_none());
}
assert_eq!(count, none.get_refcnt(py));
assert_eq!(count, obj.get_refcnt());
});
}

View File

@ -395,18 +395,18 @@ mod tests {
#[test]
fn test_set_item_refcnt() {
Python::with_gil(|py| {
let obj = py.eval("object()", None, None).unwrap();
let cnt;
{
let _pool = unsafe { crate::GILPool::new() };
let v = vec![2];
let ob = v.to_object(py);
let list: &PyList = ob.downcast(py).unwrap();
let none = py.None();
cnt = none.get_refcnt(py);
list.set_item(0, none).unwrap();
cnt = obj.get_refcnt();
list.set_item(0, obj).unwrap();
}
assert_eq!(cnt, py.None().get_refcnt(py));
assert_eq!(cnt, obj.get_refcnt());
});
}
@ -431,15 +431,15 @@ mod tests {
fn test_insert_refcnt() {
Python::with_gil(|py| {
let cnt;
let obj = py.eval("object()", None, None).unwrap();
{
let _pool = unsafe { crate::GILPool::new() };
let list = PyList::empty(py);
let none = py.None();
cnt = none.get_refcnt(py);
list.insert(0, none).unwrap();
cnt = obj.get_refcnt();
list.insert(0, obj).unwrap();
}
assert_eq!(cnt, py.None().get_refcnt(py));
assert_eq!(cnt, obj.get_refcnt());
});
}
@ -457,14 +457,14 @@ mod tests {
fn test_append_refcnt() {
Python::with_gil(|py| {
let cnt;
let obj = py.eval("object()", None, None).unwrap();
{
let _pool = unsafe { crate::GILPool::new() };
let list = PyList::empty(py);
let none = py.None();
cnt = none.get_refcnt(py);
list.append(none).unwrap();
cnt = obj.get_refcnt();
list.append(obj).unwrap();
}
assert_eq!(cnt, py.None().get_refcnt(py));
assert_eq!(cnt, obj.get_refcnt());
});
}