Skip to main content

pyo3_ffi/
object.rs

1use crate::pyport::{Py_hash_t, Py_ssize_t};
2// these re-exports are pub because it would be awkward to
3// thread the different origins for these types on this build
4// everywhere else
5#[cfg(Py_3_15)]
6use crate::PySlot;
7#[cfg(Py_LIMITED_API)]
8pub use crate::pytypedefs::PyTypeObject;
9#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
10pub use crate::pytypedefs::{PyObject, PyVarObject};
11#[cfg(all(Py_GIL_DISABLED, not(Py_LIMITED_API)))]
12use crate::{PyMutex, refcount};
13use core::ffi::{c_char, c_int, c_uint, c_ulong, c_void};
14use core::mem;
15#[cfg(all(Py_GIL_DISABLED, not(Py_LIMITED_API)))]
16use core::sync::atomic::{AtomicIsize, AtomicU32};
17
18#[cfg(not(Py_LIMITED_API))]
19pub use crate::cpython::object::PyTypeObject;
20
21// skip PyObject_HEAD
22
23#[repr(C)]
24#[derive(Copy, Clone)]
25#[cfg(all(
26    target_pointer_width = "64",
27    Py_3_14,
28    not(Py_GIL_DISABLED),
29    target_endian = "big"
30))]
31/// This struct is anonymous in CPython, so the name was given by PyO3 because
32/// Rust structs need a name.
33pub struct PyObjectObFlagsAndRefcnt {
34    pub ob_flags: u16,
35    pub ob_overflow: u16,
36    pub ob_refcnt: u32,
37}
38
39#[repr(C)]
40#[derive(Copy, Clone)]
41#[cfg(all(
42    target_pointer_width = "64",
43    Py_3_14,
44    not(Py_GIL_DISABLED),
45    target_endian = "little"
46))]
47/// This struct is anonymous in CPython, so the name was given by PyO3 because
48/// Rust structs need a name.
49pub struct PyObjectObFlagsAndRefcnt {
50    pub ob_refcnt: u32,
51    pub ob_overflow: u16,
52    pub ob_flags: u16,
53}
54
55// 4-byte alignment comes from value of _PyObject_MIN_ALIGNMENT
56
57#[cfg(all(not(Py_GIL_DISABLED), Py_3_15))]
58#[repr(C, align(4))]
59#[derive(Copy, Clone)]
60struct Aligner(c_char);
61
62#[repr(C)]
63#[derive(Copy, Clone)]
64#[cfg(all(all(Py_3_12, not(PyPy)), not(Py_GIL_DISABLED)))]
65/// This union is anonymous in CPython, so the name was given by PyO3 because
66/// Rust union need a name.
67pub union PyObjectObRefcnt {
68    #[cfg(all(target_pointer_width = "64", Py_3_14))]
69    pub ob_refcnt_full: crate::PY_INT64_T,
70    #[cfg(all(target_pointer_width = "64", Py_3_14))]
71    pub refcnt_and_flags: PyObjectObFlagsAndRefcnt,
72    pub ob_refcnt: Py_ssize_t,
73    #[cfg(all(target_pointer_width = "64", not(Py_3_14)))]
74    pub ob_refcnt_split: [crate::PY_UINT32_T; 2],
75    #[cfg(all(not(Py_GIL_DISABLED), Py_3_15))]
76    _aligner: Aligner,
77}
78
79#[cfg(all(all(Py_3_12, not(PyPy)), not(Py_GIL_DISABLED)))]
80impl core::fmt::Debug for PyObjectObRefcnt {
81    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82        // SAFETY: always valid to print `ob_refcnt` as a number
83        write!(f, "{}", unsafe { self.ob_refcnt })
84    }
85}
86
87#[cfg(all(not(all(Py_3_12, not(PyPy))), not(Py_GIL_DISABLED)))]
88pub type PyObjectObRefcnt = Py_ssize_t;
89
90const _PyObject_MIN_ALIGNMENT: usize = 4;
91
92// PyObject_HEAD_INIT comes before the PyObject definition in object.h
93// but we put it after PyObject because HEAD_INIT uses PyObject
94
95// repr(align(4)) corresponds to the use of _Py_ALIGNED_DEF in object.h. It is
96// not currently possible to use constant variables with repr(align()), see
97// https://github.com/rust-lang/rust/issues/52840
98
99#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
100#[cfg_attr(not(all(Py_3_15, Py_GIL_DISABLED)), repr(C))]
101#[cfg_attr(all(Py_3_15, Py_GIL_DISABLED), repr(C, align(4)))]
102#[derive(Debug)]
103pub struct PyObject {
104    #[cfg(Py_GIL_DISABLED)]
105    pub ob_tid: libc::uintptr_t,
106    #[cfg(all(Py_GIL_DISABLED, not(Py_3_14)))]
107    pub _padding: u16,
108    #[cfg(all(Py_GIL_DISABLED, Py_3_14))]
109    pub ob_flags: u16,
110    #[cfg(Py_GIL_DISABLED)]
111    pub ob_mutex: PyMutex, // per-object lock
112    #[cfg(Py_GIL_DISABLED)]
113    pub ob_gc_bits: u8, // gc-related state
114    #[cfg(Py_GIL_DISABLED)]
115    pub ob_ref_local: AtomicU32, // local reference count
116    #[cfg(Py_GIL_DISABLED)]
117    pub ob_ref_shared: AtomicIsize, // shared reference count
118    #[cfg(not(Py_GIL_DISABLED))]
119    pub ob_refcnt: PyObjectObRefcnt,
120    #[cfg(all(PyPy, not(Py_3_12)))]
121    pub ob_pypy_link: Py_ssize_t,
122    pub ob_type: *mut PyTypeObject,
123}
124
125#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
126const _: () = assert!(core::mem::align_of::<PyObject>() >= _PyObject_MIN_ALIGNMENT);
127
128#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
129#[allow(
130    clippy::declare_interior_mutable_const,
131    reason = "contains atomic refcount on free-threaded builds"
132)]
133pub const PyObject_HEAD_INIT: PyObject = PyObject {
134    #[cfg(Py_GIL_DISABLED)]
135    ob_tid: 0,
136    #[cfg(all(Py_GIL_DISABLED, Py_3_15))]
137    ob_flags: refcount::_Py_STATICALLY_ALLOCATED_FLAG as u16,
138    #[cfg(all(Py_GIL_DISABLED, all(Py_3_14, not(Py_3_15))))]
139    ob_flags: 0,
140    #[cfg(all(Py_GIL_DISABLED, not(Py_3_14)))]
141    _padding: 0,
142    #[cfg(Py_GIL_DISABLED)]
143    ob_mutex: PyMutex::new(),
144    #[cfg(Py_GIL_DISABLED)]
145    ob_gc_bits: 0,
146    #[cfg(Py_GIL_DISABLED)]
147    ob_ref_local: AtomicU32::new(refcount::_Py_IMMORTAL_REFCNT_LOCAL),
148    #[cfg(Py_GIL_DISABLED)]
149    ob_ref_shared: AtomicIsize::new(0),
150    #[cfg(all(not(Py_GIL_DISABLED), not(PyPy), Py_3_12))]
151    ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 },
152    #[cfg(any(not(Py_3_12), PyPy))]
153    ob_refcnt: 1,
154    #[cfg(all(PyPy, not(Py_3_12)))]
155    ob_pypy_link: 0,
156    ob_type: core::ptr::null_mut(),
157};
158
159// skipped _Py_UNOWNED_TID
160
161// skipped _PyObject_CAST
162
163#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
164#[repr(C)]
165#[derive(Debug)]
166pub struct PyVarObject {
167    pub ob_base: PyObject,
168    #[cfg(not(GraalPy))]
169    pub ob_size: Py_ssize_t,
170    // On GraalPy the field is physically there, but not always populated. We hide it to prevent accidental misuse
171    #[cfg(GraalPy)]
172    _ob_size_graalpy: Py_ssize_t,
173}
174
175#[inline]
176pub(crate) unsafe fn _PyVarObject_CAST(op: *mut PyObject) -> *mut PyVarObject {
177    op.cast()
178}
179
180#[inline]
181#[cfg(not(any(GraalPy, PyPy, RustPython)))]
182#[cfg_attr(docsrs, doc(cfg(all())))]
183pub unsafe fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int {
184    (x == y).into()
185}
186
187#[cfg(any(GraalPy, PyPy, RustPython))]
188#[cfg_attr(docsrs, doc(cfg(all())))]
189extern_libpython! {
190    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPy_Is")]
191    pub fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int;
192}
193
194// skipped _Py_GetThreadLocal_Addr
195
196// skipped _Py_ThreadID
197
198// skipped _Py_IsOwnedByCurrentThread
199
200#[cfg(GraalPy)]
201extern_libpython! {
202    #[cfg(GraalPy)]
203    fn _Py_TYPE(arg1: *const PyObject) -> *mut PyTypeObject;
204
205    #[cfg(GraalPy)]
206    fn _Py_SIZE(arg1: *const PyObject) -> Py_ssize_t;
207}
208
209#[inline]
210#[cfg(not(all(Py_LIMITED_API, Py_3_14)))]
211pub unsafe fn Py_TYPE(ob: *mut PyObject) -> *mut PyTypeObject {
212    #[cfg(not(GraalPy))]
213    return (*ob).ob_type;
214    #[cfg(GraalPy)]
215    return _Py_TYPE(ob);
216}
217
218#[cfg(all(Py_LIMITED_API, Py_3_14))]
219extern_libpython! {
220    #[cfg_attr(PyPy, link_name = "PyPy_TYPE")]
221    pub fn Py_TYPE(ob: *mut PyObject) -> *mut PyTypeObject;
222}
223
224// skip _Py_TYPE compat shim
225
226#[cfg(not(RustPython))]
227extern_libpython! {
228    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyLong_Type")]
229    pub static mut PyLong_Type: PyTypeObject;
230    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyBool_Type")]
231    pub static mut PyBool_Type: PyTypeObject;
232}
233
234#[cfg(not(all(Py_LIMITED_API, Py_3_15)))]
235#[inline]
236#[cfg(not(RustPython))]
237pub unsafe fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t {
238    #[cfg(not(GraalPy))]
239    {
240        debug_assert_ne!((*ob).ob_type, &raw mut crate::PyLong_Type);
241        debug_assert_ne!((*ob).ob_type, &raw mut crate::PyBool_Type);
242        (*ob.cast::<PyVarObject>()).ob_size
243    }
244    #[cfg(GraalPy)]
245    _Py_SIZE(ob)
246}
247
248extern_libpython! {
249    #[cfg(RustPython)]
250    pub fn Py_SIZE(ob: *mut PyObject) -> Py_ssize_t;
251    #[cfg(any(all(Py_LIMITED_API, Py_3_15), RustPython))]
252    pub fn Py_IS_TYPE(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int;
253}
254
255#[inline]
256#[cfg(not(any(all(Py_LIMITED_API, Py_3_15), RustPython)))]
257pub unsafe fn Py_IS_TYPE(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int {
258    (Py_TYPE(ob) == tp) as c_int
259}
260
261// skipped Py_SET_TYPE
262
263// skipped Py_SET_SIZE
264
265pub type unaryfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
266pub type binaryfunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject;
267pub type ternaryfunc =
268    unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> *mut PyObject;
269pub type inquiry = unsafe extern "C" fn(*mut PyObject) -> c_int;
270pub type lenfunc = unsafe extern "C" fn(*mut PyObject) -> Py_ssize_t;
271pub type ssizeargfunc = unsafe extern "C" fn(*mut PyObject, Py_ssize_t) -> *mut PyObject;
272pub type ssizessizeargfunc =
273    unsafe extern "C" fn(*mut PyObject, Py_ssize_t, Py_ssize_t) -> *mut PyObject;
274pub type ssizeobjargproc = unsafe extern "C" fn(*mut PyObject, Py_ssize_t, *mut PyObject) -> c_int;
275pub type ssizessizeobjargproc =
276    unsafe extern "C" fn(*mut PyObject, Py_ssize_t, Py_ssize_t, arg4: *mut PyObject) -> c_int;
277pub type objobjargproc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
278
279pub type objobjproc = unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> c_int;
280pub type visitproc = unsafe extern "C" fn(object: *mut PyObject, arg: *mut c_void) -> c_int;
281pub type traverseproc =
282    unsafe extern "C" fn(slf: *mut PyObject, visit: visitproc, arg: *mut c_void) -> c_int;
283
284pub type freefunc = unsafe extern "C" fn(*mut c_void);
285pub type destructor = unsafe extern "C" fn(*mut PyObject);
286pub type getattrfunc = unsafe extern "C" fn(*mut PyObject, *mut c_char) -> *mut PyObject;
287pub type getattrofunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject;
288pub type setattrfunc = unsafe extern "C" fn(*mut PyObject, *mut c_char, *mut PyObject) -> c_int;
289pub type setattrofunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
290pub type reprfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
291pub type hashfunc = unsafe extern "C" fn(*mut PyObject) -> Py_hash_t;
292pub type richcmpfunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, c_int) -> *mut PyObject;
293pub type getiterfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
294pub type iternextfunc = unsafe extern "C" fn(*mut PyObject) -> *mut PyObject;
295#[cfg(Py_3_15)]
296#[repr(C)]
297pub struct _PyObjectIndexPair {
298    pub object: *mut PyObject,
299    pub index: Py_ssize_t,
300}
301#[cfg(Py_3_15)]
302pub type _Py_iteritemfunc = unsafe extern "C" fn(*mut PyObject, Py_ssize_t) -> _PyObjectIndexPair;
303pub type descrgetfunc =
304    unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> *mut PyObject;
305pub type descrsetfunc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
306pub type initproc = unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> c_int;
307pub type newfunc =
308    unsafe extern "C" fn(*mut PyTypeObject, *mut PyObject, *mut PyObject) -> *mut PyObject;
309pub type allocfunc = unsafe extern "C" fn(*mut PyTypeObject, Py_ssize_t) -> *mut PyObject;
310pub type vectorcallfunc = unsafe extern "C" fn(
311    callable: *mut PyObject,
312    args: *const *mut PyObject,
313    nargsf: libc::size_t,
314    kwnames: *mut PyObject,
315) -> *mut PyObject;
316
317#[repr(C)]
318#[derive(Copy, Clone)]
319pub struct PyType_Slot {
320    pub slot: c_int,
321    pub pfunc: *mut c_void,
322}
323
324impl Default for PyType_Slot {
325    fn default() -> PyType_Slot {
326        // SAFETY: CPython treats a zeroed slot as a sentinel value to mean the end of the slots array.
327        unsafe { mem::zeroed() }
328    }
329}
330
331#[repr(C)]
332#[derive(Copy, Clone)]
333pub struct PyType_Spec {
334    pub name: *const c_char,
335    pub basicsize: c_int,
336    pub itemsize: c_int,
337    pub flags: c_uint,
338    pub slots: *mut PyType_Slot,
339}
340
341extern_libpython! {
342    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_FromSpec")]
343    pub fn PyType_FromSpec(arg1: *mut PyType_Spec) -> *mut PyObject;
344
345    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_FromSpecWithBases")]
346    pub fn PyType_FromSpecWithBases(arg1: *mut PyType_Spec, arg2: *mut PyObject) -> *mut PyObject;
347
348    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GetSlot")]
349    pub fn PyType_GetSlot(arg1: *mut PyTypeObject, arg2: c_int) -> *mut c_void;
350
351    #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
352    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_FromModuleAndSpec")]
353    pub fn PyType_FromModuleAndSpec(
354        module: *mut PyObject,
355        spec: *mut PyType_Spec,
356        bases: *mut PyObject,
357    ) -> *mut PyObject;
358
359    #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
360    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GetModule")]
361    pub fn PyType_GetModule(arg1: *mut PyTypeObject) -> *mut PyObject;
362
363    #[cfg(any(Py_3_10, not(Py_LIMITED_API)))]
364    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GetModuleState")]
365    pub fn PyType_GetModuleState(arg1: *mut PyTypeObject) -> *mut c_void;
366
367    #[cfg(Py_3_11)]
368    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GetName")]
369    pub fn PyType_GetName(arg1: *mut PyTypeObject) -> *mut PyObject;
370
371    #[cfg(Py_3_11)]
372    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GetQualName")]
373    pub fn PyType_GetQualName(arg1: *mut PyTypeObject) -> *mut PyObject;
374
375    #[cfg(Py_3_13)]
376    #[cfg_attr(PyPy, link_name = "PyPyType_GetFullyQualifiedName")]
377    pub fn PyType_GetFullyQualifiedName(arg1: *mut PyTypeObject) -> *mut PyObject;
378
379    #[cfg(Py_3_13)]
380    #[cfg_attr(PyPy, link_name = "PyPyType_GetModuleName")]
381    pub fn PyType_GetModuleName(arg1: *mut PyTypeObject) -> *mut PyObject;
382
383    #[cfg(Py_3_12)]
384    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_FromMetaclass")]
385    pub fn PyType_FromMetaclass(
386        metaclass: *mut PyTypeObject,
387        module: *mut PyObject,
388        spec: *mut PyType_Spec,
389        bases: *mut PyObject,
390    ) -> *mut PyObject;
391
392    #[cfg(Py_3_12)]
393    pub fn PyObject_GetTypeData(obj: *mut PyObject, cls: *mut PyTypeObject) -> *mut c_void;
394
395    #[cfg(Py_3_12)]
396    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GetTypeDataSize")]
397    pub fn PyType_GetTypeDataSize(cls: *mut PyTypeObject) -> Py_ssize_t;
398
399    #[cfg(Py_3_14)]
400    #[cfg_attr(PyPy, link_name = "PyPyType_GetBaseByToken")]
401    pub fn PyType_GetBaseByToken(
402        type_: *mut PyTypeObject,
403        token: *mut c_void,
404        result: *mut *mut PyTypeObject,
405    ) -> c_int;
406
407    #[cfg(Py_3_15)]
408    #[cfg_attr(PyPy, link_name = "PyPyType_FromSlot")]
409    pub fn PyType_FromSlots(slots: *mut PySlot) -> *mut PyObject;
410
411    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_IsSubtype")]
412    pub fn PyType_IsSubtype(a: *mut PyTypeObject, b: *mut PyTypeObject) -> c_int;
413}
414
415#[inline]
416pub unsafe fn PyObject_TypeCheck(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int {
417    (Py_IS_TYPE(ob, tp) != 0 || PyType_IsSubtype(Py_TYPE(ob), tp) != 0) as c_int
418}
419
420extern_libpython! {
421    /// built-in 'type'
422    #[cfg(not(RustPython))]
423    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_Type")]
424    pub static mut PyType_Type: PyTypeObject;
425    /// built-in 'object'
426    #[cfg(not(RustPython))]
427    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyBaseObject_Type")]
428    pub static mut PyBaseObject_Type: PyTypeObject;
429    /// built-in 'super'
430    #[cfg(not(RustPython))]
431    pub static mut PySuper_Type: PyTypeObject;
432
433    pub fn PyType_GetFlags(arg1: *mut PyTypeObject) -> c_ulong;
434
435    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_Ready")]
436    pub fn PyType_Ready(t: *mut PyTypeObject) -> c_int;
437    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GenericAlloc")]
438    pub fn PyType_GenericAlloc(t: *mut PyTypeObject, nitems: Py_ssize_t) -> *mut PyObject;
439    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_GenericNew")]
440    pub fn PyType_GenericNew(
441        t: *mut PyTypeObject,
442        args: *mut PyObject,
443        kwds: *mut PyObject,
444    ) -> *mut PyObject;
445    pub fn PyType_ClearCache() -> c_uint;
446    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_Modified")]
447    pub fn PyType_Modified(t: *mut PyTypeObject);
448
449    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_Repr")]
450    pub fn PyObject_Repr(o: *mut PyObject) -> *mut PyObject;
451    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_Str")]
452    pub fn PyObject_Str(o: *mut PyObject) -> *mut PyObject;
453    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_ASCII")]
454    pub fn PyObject_ASCII(arg1: *mut PyObject) -> *mut PyObject;
455    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_Bytes")]
456    pub fn PyObject_Bytes(arg1: *mut PyObject) -> *mut PyObject;
457    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_RichCompare")]
458    pub fn PyObject_RichCompare(
459        arg1: *mut PyObject,
460        arg2: *mut PyObject,
461        arg3: c_int,
462    ) -> *mut PyObject;
463    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_RichCompareBool")]
464    pub fn PyObject_RichCompareBool(arg1: *mut PyObject, arg2: *mut PyObject, arg3: c_int)
465    -> c_int;
466    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_GetAttrString")]
467    pub fn PyObject_GetAttrString(arg1: *mut PyObject, arg2: *const c_char) -> *mut PyObject;
468    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_SetAttrString")]
469    pub fn PyObject_SetAttrString(
470        arg1: *mut PyObject,
471        arg2: *const c_char,
472        arg3: *mut PyObject,
473    ) -> c_int;
474    #[cfg(any(Py_3_13, all(PyPy, not(Py_3_11))))] // CPython defined in 3.12 as an inline function in abstract.h
475    #[cfg_attr(PyPy, link_name = "PyPyObject_DelAttrString")]
476    pub fn PyObject_DelAttrString(arg1: *mut PyObject, arg2: *const c_char) -> c_int;
477    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_HasAttrString")]
478    pub fn PyObject_HasAttrString(arg1: *mut PyObject, arg2: *const c_char) -> c_int;
479    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_GetAttr")]
480    pub fn PyObject_GetAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject;
481    #[cfg(Py_3_13)]
482    #[cfg_attr(PyPy, link_name = "PyPyObject_GetOptionalAttr")]
483    pub fn PyObject_GetOptionalAttr(
484        arg1: *mut PyObject,
485        arg2: *mut PyObject,
486        arg3: *mut *mut PyObject,
487    ) -> c_int;
488    #[cfg(Py_3_13)]
489    #[cfg_attr(PyPy, link_name = "PyPyObject_GetOptionalAttrString")]
490    pub fn PyObject_GetOptionalAttrString(
491        arg1: *mut PyObject,
492        arg2: *const c_char,
493        arg3: *mut *mut PyObject,
494    ) -> c_int;
495    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_SetAttr")]
496    pub fn PyObject_SetAttr(arg1: *mut PyObject, arg2: *mut PyObject, arg3: *mut PyObject)
497    -> c_int;
498    #[cfg(any(Py_3_13, all(PyPy, not(Py_3_11))))] // CPython defined in 3.12 as an inline function in abstract.h
499    #[cfg_attr(PyPy, link_name = "PyPyObject_DelAttr")]
500    pub fn PyObject_DelAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int;
501    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_HasAttr")]
502    pub fn PyObject_HasAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int;
503    #[cfg(Py_3_13)]
504    #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttrWithError")]
505    pub fn PyObject_HasAttrWithError(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int;
506    #[cfg(Py_3_13)]
507    #[cfg_attr(PyPy, link_name = "PyPyObject_HasAttrStringWithError")]
508    pub fn PyObject_HasAttrStringWithError(arg1: *mut PyObject, arg2: *const c_char) -> c_int;
509    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_SelfIter")]
510    pub fn PyObject_SelfIter(arg1: *mut PyObject) -> *mut PyObject;
511    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_GenericGetAttr")]
512    pub fn PyObject_GenericGetAttr(arg1: *mut PyObject, arg2: *mut PyObject) -> *mut PyObject;
513    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_GenericSetAttr")]
514    pub fn PyObject_GenericSetAttr(
515        arg1: *mut PyObject,
516        arg2: *mut PyObject,
517        arg3: *mut PyObject,
518    ) -> c_int;
519    #[cfg(not(all(Py_LIMITED_API, not(Py_3_10))))]
520    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_GenericGetDict")]
521    pub fn PyObject_GenericGetDict(arg1: *mut PyObject, arg2: *mut c_void) -> *mut PyObject;
522    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_GenericSetDict")]
523    pub fn PyObject_GenericSetDict(
524        arg1: *mut PyObject,
525        arg2: *mut PyObject,
526        arg3: *mut c_void,
527    ) -> c_int;
528    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_Hash")]
529    pub fn PyObject_Hash(arg1: *mut PyObject) -> Py_hash_t;
530    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_HashNotImplemented")]
531    pub fn PyObject_HashNotImplemented(arg1: *mut PyObject) -> Py_hash_t;
532    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_IsTrue")]
533    pub fn PyObject_IsTrue(arg1: *mut PyObject) -> c_int;
534    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_Not")]
535    pub fn PyObject_Not(arg1: *mut PyObject) -> c_int;
536    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyCallable_Check")]
537    pub fn PyCallable_Check(arg1: *mut PyObject) -> c_int;
538    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_ClearWeakRefs")]
539    pub fn PyObject_ClearWeakRefs(arg1: *mut PyObject);
540
541    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyObject_Dir")]
542    pub fn PyObject_Dir(arg1: *mut PyObject) -> *mut PyObject;
543    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPy_ReprEnter")]
544    pub fn Py_ReprEnter(arg1: *mut PyObject) -> c_int;
545    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPy_ReprLeave")]
546    pub fn Py_ReprLeave(arg1: *mut PyObject);
547}
548
549// Flag bits for printing:
550pub const Py_PRINT_RAW: c_int = 1; // No string quotes etc.
551
552// skipped because is a private API
553// const _Py_TPFLAGS_STATIC_BUILTIN: c_ulong = 1 << 1;
554
555#[cfg(all(Py_3_12, not(Py_LIMITED_API)))]
556pub const Py_TPFLAGS_MANAGED_WEAKREF: c_ulong = 1 << 3;
557
558#[cfg(all(Py_3_11, not(Py_LIMITED_API)))]
559pub const Py_TPFLAGS_MANAGED_DICT: c_ulong = 1 << 4;
560
561#[cfg(all(Py_3_10, not(Py_LIMITED_API)))]
562pub const Py_TPFLAGS_SEQUENCE: c_ulong = 1 << 5;
563
564#[cfg(all(Py_3_10, not(Py_LIMITED_API)))]
565pub const Py_TPFLAGS_MAPPING: c_ulong = 1 << 6;
566
567#[cfg(Py_3_10)]
568pub const Py_TPFLAGS_DISALLOW_INSTANTIATION: c_ulong = 1 << 7;
569
570#[cfg(Py_3_10)]
571pub const Py_TPFLAGS_IMMUTABLETYPE: c_ulong = 1 << 8;
572
573/// Set if the type object is dynamically allocated
574pub const Py_TPFLAGS_HEAPTYPE: c_ulong = 1 << 9;
575
576/// Set if the type allows subclassing
577pub const Py_TPFLAGS_BASETYPE: c_ulong = 1 << 10;
578
579/// Set if the type implements the vectorcall protocol (PEP 590)
580#[cfg(any(Py_3_12, not(Py_LIMITED_API)))]
581pub const Py_TPFLAGS_HAVE_VECTORCALL: c_ulong = 1 << 11;
582// skipped backwards-compatibility alias _Py_TPFLAGS_HAVE_VECTORCALL
583
584/// Set if the type is 'ready' -- fully initialized
585pub const Py_TPFLAGS_READY: c_ulong = 1 << 12;
586
587/// Set while the type is being 'readied', to prevent recursive ready calls
588pub const Py_TPFLAGS_READYING: c_ulong = 1 << 13;
589
590/// Objects support garbage collection (see objimp.h)
591pub const Py_TPFLAGS_HAVE_GC: c_ulong = 1 << 14;
592
593const Py_TPFLAGS_HAVE_STACKLESS_EXTENSION: c_ulong = 0;
594pub const Py_TPFLAGS_METHOD_DESCRIPTOR: c_ulong = 1 << 17;
595
596pub const Py_TPFLAGS_VALID_VERSION_TAG: c_ulong = 1 << 19;
597
598/* Type is abstract and cannot be instantiated */
599pub const Py_TPFLAGS_IS_ABSTRACT: c_ulong = 1 << 20;
600
601// skipped non-limited / 3.10 Py_TPFLAGS_HAVE_AM_SEND
602#[cfg(Py_3_12)]
603pub const Py_TPFLAGS_ITEMS_AT_END: c_ulong = 1 << 23;
604
605/* These flags are used to determine if a type is a subclass. */
606pub const Py_TPFLAGS_LONG_SUBCLASS: c_ulong = 1 << 24;
607pub const Py_TPFLAGS_LIST_SUBCLASS: c_ulong = 1 << 25;
608pub const Py_TPFLAGS_TUPLE_SUBCLASS: c_ulong = 1 << 26;
609pub const Py_TPFLAGS_BYTES_SUBCLASS: c_ulong = 1 << 27;
610pub const Py_TPFLAGS_UNICODE_SUBCLASS: c_ulong = 1 << 28;
611pub const Py_TPFLAGS_DICT_SUBCLASS: c_ulong = 1 << 29;
612pub const Py_TPFLAGS_BASE_EXC_SUBCLASS: c_ulong = 1 << 30;
613pub const Py_TPFLAGS_TYPE_SUBCLASS: c_ulong = 1 << 31;
614
615pub const Py_TPFLAGS_DEFAULT: c_ulong = if cfg!(Py_3_10) {
616    Py_TPFLAGS_HAVE_STACKLESS_EXTENSION
617} else {
618    Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | Py_TPFLAGS_HAVE_VERSION_TAG
619};
620
621pub const Py_TPFLAGS_HAVE_FINALIZE: c_ulong = 1;
622pub const Py_TPFLAGS_HAVE_VERSION_TAG: c_ulong = 1 << 18;
623
624#[cfg(Py_3_13)]
625pub const Py_CONSTANT_NONE: c_uint = 0;
626#[cfg(Py_3_13)]
627pub const Py_CONSTANT_FALSE: c_uint = 1;
628#[cfg(Py_3_13)]
629pub const Py_CONSTANT_TRUE: c_uint = 2;
630#[cfg(Py_3_13)]
631pub const Py_CONSTANT_ELLIPSIS: c_uint = 3;
632#[cfg(Py_3_13)]
633pub const Py_CONSTANT_NOT_IMPLEMENTED: c_uint = 4;
634#[cfg(Py_3_13)]
635pub const Py_CONSTANT_ZERO: c_uint = 5;
636#[cfg(Py_3_13)]
637pub const Py_CONSTANT_ONE: c_uint = 6;
638#[cfg(Py_3_13)]
639pub const Py_CONSTANT_EMPTY_STR: c_uint = 7;
640#[cfg(Py_3_13)]
641pub const Py_CONSTANT_EMPTY_BYTES: c_uint = 8;
642#[cfg(Py_3_13)]
643pub const Py_CONSTANT_EMPTY_TUPLE: c_uint = 9;
644
645extern_libpython! {
646    #[cfg(Py_3_13)]
647    #[cfg_attr(PyPy, link_name = "PyPy_GetConstant")]
648    pub fn Py_GetConstant(constant_id: c_uint) -> *mut PyObject;
649    #[cfg(Py_3_13)]
650    #[cfg_attr(PyPy, link_name = "PyPy_GetConstantBorrowed")]
651    pub fn Py_GetConstantBorrowed(constant_id: c_uint) -> *mut PyObject;
652
653    #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))]
654    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPy_NoneStruct")]
655    static mut _Py_NoneStruct: PyObject;
656
657    #[cfg(GraalPy)]
658    static mut _Py_NoneStructReference: *mut PyObject;
659}
660
661#[inline]
662pub unsafe fn Py_None() -> *mut PyObject {
663    #[cfg(all(not(GraalPy), all(Py_3_13, Py_LIMITED_API)))]
664    return Py_GetConstantBorrowed(Py_CONSTANT_NONE);
665
666    #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))]
667    return &raw mut _Py_NoneStruct;
668
669    #[cfg(GraalPy)]
670    return _Py_NoneStructReference;
671}
672
673#[inline]
674pub unsafe fn Py_IsNone(x: *mut PyObject) -> c_int {
675    Py_Is(x, Py_None())
676}
677
678// skipped Py_RETURN_NONE
679
680extern_libpython! {
681    #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))]
682    #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPy_NotImplementedStruct")]
683    static mut _Py_NotImplementedStruct: PyObject;
684
685    #[cfg(GraalPy)]
686    static mut _Py_NotImplementedStructReference: *mut PyObject;
687}
688
689#[inline]
690pub unsafe fn Py_NotImplemented() -> *mut PyObject {
691    #[cfg(all(not(GraalPy), all(Py_3_13, Py_LIMITED_API)))]
692    return Py_GetConstantBorrowed(Py_CONSTANT_NOT_IMPLEMENTED);
693
694    #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))]
695    return &raw mut _Py_NotImplementedStruct;
696
697    #[cfg(GraalPy)]
698    return _Py_NotImplementedStructReference;
699}
700
701// skipped Py_RETURN_NOTIMPLEMENTED
702
703/* Rich comparison opcodes */
704pub const Py_LT: c_int = 0;
705pub const Py_LE: c_int = 1;
706pub const Py_EQ: c_int = 2;
707pub const Py_NE: c_int = 3;
708pub const Py_GT: c_int = 4;
709pub const Py_GE: c_int = 5;
710
711#[cfg(Py_3_10)]
712#[repr(C)]
713#[derive(Copy, Clone, Debug, PartialEq, Eq)]
714pub enum PySendResult {
715    PYGEN_RETURN = 0,
716    PYGEN_ERROR = -1,
717    PYGEN_NEXT = 1,
718}
719
720// skipped Py_RETURN_RICHCOMPARE
721
722#[inline]
723pub unsafe fn PyType_HasFeature(ty: *mut PyTypeObject, feature: c_ulong) -> c_int {
724    #[cfg(Py_LIMITED_API)]
725    let flags = PyType_GetFlags(ty);
726
727    #[cfg(all(not(Py_LIMITED_API), Py_GIL_DISABLED))]
728    let flags = (*ty).tp_flags.load(core::sync::atomic::Ordering::Relaxed);
729
730    #[cfg(all(not(Py_LIMITED_API), not(Py_GIL_DISABLED)))]
731    let flags = (*ty).tp_flags;
732
733    ((flags & feature) != 0) as c_int
734}
735
736#[inline]
737#[cfg(not(RustPython))]
738pub unsafe fn PyType_FastSubclass(t: *mut PyTypeObject, f: c_ulong) -> c_int {
739    PyType_HasFeature(t, f)
740}
741
742#[inline]
743#[cfg(not(RustPython))]
744pub unsafe fn PyType_Check(op: *mut PyObject) -> c_int {
745    PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS)
746}
747
748// skipped _PyType_CAST
749
750#[inline]
751#[cfg(not(RustPython))]
752pub unsafe fn PyType_CheckExact(op: *mut PyObject) -> c_int {
753    Py_IS_TYPE(op, &raw mut PyType_Type)
754}
755
756extern_libpython! {
757    #[cfg(RustPython)]
758    pub fn PyType_Check(op: *mut PyObject) -> c_int;
759    #[cfg(RustPython)]
760    pub fn PyType_CheckExact(op: *mut PyObject) -> c_int;
761
762    #[cfg(any(Py_3_13, all(Py_3_11, not(Py_LIMITED_API))))]
763    #[cfg_attr(PyPy, link_name = "PyPyType_GetModuleByDef")]
764    pub fn PyType_GetModuleByDef(
765        arg1: *mut crate::PyTypeObject,
766        arg2: *mut crate::PyModuleDef,
767    ) -> *mut PyObject;
768
769    #[cfg(Py_3_14)]
770    pub fn PyType_Freeze(tp: *mut crate::PyTypeObject) -> c_int;
771
772    #[cfg(any(Py_3_15, not(Py_LIMITED_API)))]
773    #[cfg_attr(PyPy, link_name = "PyPyObject_CallFinalizerFromDealloc")]
774    pub fn PyObject_CallFinalizerFromDealloc(arg1: *mut crate::PyObject) -> c_int;
775
776    #[cfg(Py_3_15)]
777    pub fn PyType_GetModuleByToken(_type: *mut PyTypeObject, token: *const c_void)
778    -> *mut PyObject;
779
780    #[cfg(Py_3_15)]
781    pub fn PyObject_GetTypeData_DuringGC(o: *mut PyObject, cls: *mut PyTypeObject) -> *mut c_void;
782
783    #[cfg(Py_3_15)]
784    pub fn PyType_GetModuleState_DuringGC(type_: *mut PyTypeObject) -> *mut c_void;
785
786    #[cfg(Py_3_15)]
787    pub fn PyType_GetBaseByToken_DuringGC(
788        type_: *mut PyTypeObject,
789        tp_token: *mut c_void,
790        result: *mut *mut PyTypeObject,
791    ) -> c_int;
792
793    #[cfg(Py_3_15)]
794    pub fn PyType_GetModule_DuringGC(type_: *mut PyTypeObject) -> *mut PyObject;
795
796    #[cfg(Py_3_15)]
797    pub fn PyType_GetModuleByToken_DuringGC(
798        type_: *mut PyTypeObject,
799        mod_token: *const c_void,
800    ) -> *mut PyObject;
801}