pyo3_ffi/cpython/
abstract_.rs

1use crate::{PyObject, Py_ssize_t};
2#[cfg(any(all(Py_3_8, not(any(PyPy, GraalPy))), not(Py_3_11)))]
3use std::os::raw::c_char;
4use std::os::raw::c_int;
5
6#[cfg(not(Py_3_11))]
7use crate::Py_buffer;
8
9#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
10use crate::{
11    vectorcallfunc, PyCallable_Check, PyThreadState, PyThreadState_GET, PyTuple_Check,
12    PyType_HasFeature, Py_TPFLAGS_HAVE_VECTORCALL,
13};
14#[cfg(Py_3_8)]
15use libc::size_t;
16
17extern "C" {
18    #[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
19    pub fn _PyStack_AsDict(values: *const *mut PyObject, kwnames: *mut PyObject) -> *mut PyObject;
20}
21
22#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
23const _PY_FASTCALL_SMALL_STACK: size_t = 5;
24
25extern "C" {
26    #[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
27    pub fn _Py_CheckFunctionResult(
28        tstate: *mut PyThreadState,
29        callable: *mut PyObject,
30        result: *mut PyObject,
31        where_: *const c_char,
32    ) -> *mut PyObject;
33
34    #[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
35    pub fn _PyObject_MakeTpCall(
36        tstate: *mut PyThreadState,
37        callable: *mut PyObject,
38        args: *const *mut PyObject,
39        nargs: Py_ssize_t,
40        keywords: *mut PyObject,
41    ) -> *mut PyObject;
42}
43
44#[cfg(Py_3_8)] // NB exported as public in abstract.rs from 3.12
45const PY_VECTORCALL_ARGUMENTS_OFFSET: size_t =
46    1 << (8 * std::mem::size_of::<size_t>() as size_t - 1);
47
48#[cfg(Py_3_8)]
49#[inline(always)]
50pub unsafe fn PyVectorcall_NARGS(n: size_t) -> Py_ssize_t {
51    let n = n & !PY_VECTORCALL_ARGUMENTS_OFFSET;
52    n.try_into().expect("cannot fail due to mask")
53}
54
55#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
56#[inline(always)]
57pub unsafe fn PyVectorcall_Function(callable: *mut PyObject) -> Option<vectorcallfunc> {
58    assert!(!callable.is_null());
59    let tp = crate::Py_TYPE(callable);
60    if PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL) == 0 {
61        return None;
62    }
63    assert!(PyCallable_Check(callable) > 0);
64    let offset = (*tp).tp_vectorcall_offset;
65    assert!(offset > 0);
66    let ptr = callable.cast::<c_char>().offset(offset).cast();
67    *ptr
68}
69
70#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
71#[inline(always)]
72pub unsafe fn _PyObject_VectorcallTstate(
73    tstate: *mut PyThreadState,
74    callable: *mut PyObject,
75    args: *const *mut PyObject,
76    nargsf: size_t,
77    kwnames: *mut PyObject,
78) -> *mut PyObject {
79    assert!(kwnames.is_null() || PyTuple_Check(kwnames) > 0);
80    assert!(!args.is_null() || PyVectorcall_NARGS(nargsf) == 0);
81
82    match PyVectorcall_Function(callable) {
83        None => {
84            let nargs = PyVectorcall_NARGS(nargsf);
85            _PyObject_MakeTpCall(tstate, callable, args, nargs, kwnames)
86        }
87        Some(func) => {
88            let res = func(callable, args, nargsf, kwnames);
89            _Py_CheckFunctionResult(tstate, callable, res, std::ptr::null_mut())
90        }
91    }
92}
93
94#[cfg(all(Py_3_8, not(any(PyPy, GraalPy, Py_3_11))))] // exported as a function from 3.11, see abstract.rs
95#[inline(always)]
96pub unsafe fn PyObject_Vectorcall(
97    callable: *mut PyObject,
98    args: *const *mut PyObject,
99    nargsf: size_t,
100    kwnames: *mut PyObject,
101) -> *mut PyObject {
102    _PyObject_VectorcallTstate(PyThreadState_GET(), callable, args, nargsf, kwnames)
103}
104
105extern "C" {
106    #[cfg(Py_3_8)]
107    #[cfg_attr(
108        all(not(any(PyPy, GraalPy)), not(Py_3_9)),
109        link_name = "_PyObject_VectorcallDict"
110    )]
111    #[cfg_attr(all(PyPy, not(Py_3_9)), link_name = "_PyPyObject_VectorcallDict")]
112    #[cfg_attr(all(PyPy, Py_3_9), link_name = "PyPyObject_VectorcallDict")]
113    pub fn PyObject_VectorcallDict(
114        callable: *mut PyObject,
115        args: *const *mut PyObject,
116        nargsf: size_t,
117        kwdict: *mut PyObject,
118    ) -> *mut PyObject;
119
120    #[cfg(Py_3_8)]
121    #[cfg_attr(not(any(Py_3_9, PyPy)), link_name = "_PyVectorcall_Call")]
122    #[cfg_attr(PyPy, link_name = "PyPyVectorcall_Call")]
123    pub fn PyVectorcall_Call(
124        callable: *mut PyObject,
125        tuple: *mut PyObject,
126        dict: *mut PyObject,
127    ) -> *mut PyObject;
128}
129
130#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
131#[inline(always)]
132pub unsafe fn _PyObject_FastCallTstate(
133    tstate: *mut PyThreadState,
134    func: *mut PyObject,
135    args: *const *mut PyObject,
136    nargs: Py_ssize_t,
137) -> *mut PyObject {
138    _PyObject_VectorcallTstate(tstate, func, args, nargs as size_t, std::ptr::null_mut())
139}
140
141#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
142#[inline(always)]
143pub unsafe fn _PyObject_FastCall(
144    func: *mut PyObject,
145    args: *const *mut PyObject,
146    nargs: Py_ssize_t,
147) -> *mut PyObject {
148    _PyObject_FastCallTstate(PyThreadState_GET(), func, args, nargs)
149}
150
151#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
152#[inline(always)]
153pub unsafe fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject {
154    _PyObject_VectorcallTstate(
155        PyThreadState_GET(),
156        func,
157        std::ptr::null_mut(),
158        0,
159        std::ptr::null_mut(),
160    )
161}
162
163extern "C" {
164    #[cfg(PyPy)]
165    #[link_name = "_PyPyObject_CallNoArg"]
166    pub fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject;
167}
168
169#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
170#[inline(always)]
171pub unsafe fn PyObject_CallOneArg(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject {
172    assert!(!arg.is_null());
173    let args_array = [std::ptr::null_mut(), arg];
174    let args = args_array.as_ptr().offset(1); // For PY_VECTORCALL_ARGUMENTS_OFFSET
175    let tstate = PyThreadState_GET();
176    let nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
177    _PyObject_VectorcallTstate(tstate, func, args, nargsf, std::ptr::null_mut())
178}
179
180#[cfg(all(Py_3_9, not(any(PyPy, GraalPy))))]
181#[inline(always)]
182pub unsafe fn PyObject_CallMethodNoArgs(
183    self_: *mut PyObject,
184    name: *mut PyObject,
185) -> *mut PyObject {
186    crate::PyObject_VectorcallMethod(
187        name,
188        &self_,
189        1 | PY_VECTORCALL_ARGUMENTS_OFFSET,
190        std::ptr::null_mut(),
191    )
192}
193
194#[cfg(all(Py_3_9, not(any(PyPy, GraalPy))))]
195#[inline(always)]
196pub unsafe fn PyObject_CallMethodOneArg(
197    self_: *mut PyObject,
198    name: *mut PyObject,
199    arg: *mut PyObject,
200) -> *mut PyObject {
201    let args = [self_, arg];
202    assert!(!arg.is_null());
203    crate::PyObject_VectorcallMethod(
204        name,
205        args.as_ptr(),
206        2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
207        std::ptr::null_mut(),
208    )
209}
210
211// skipped _PyObject_VectorcallMethodId
212// skipped _PyObject_CallMethodIdNoArgs
213// skipped _PyObject_CallMethodIdOneArg
214
215// skipped _PyObject_HasLen
216
217extern "C" {
218    #[cfg_attr(PyPy, link_name = "PyPyObject_LengthHint")]
219    pub fn PyObject_LengthHint(o: *mut PyObject, arg1: Py_ssize_t) -> Py_ssize_t;
220
221    #[cfg(not(Py_3_11))] // moved to src/buffer.rs from 3.11
222    #[cfg(all(Py_3_9, not(any(PyPy, GraalPy))))]
223    pub fn PyObject_CheckBuffer(obj: *mut PyObject) -> c_int;
224}
225
226#[cfg(not(any(Py_3_9, PyPy)))]
227#[inline]
228pub unsafe fn PyObject_CheckBuffer(o: *mut PyObject) -> c_int {
229    let tp_as_buffer = (*crate::Py_TYPE(o)).tp_as_buffer;
230    (!tp_as_buffer.is_null() && (*tp_as_buffer).bf_getbuffer.is_some()) as c_int
231}
232
233#[cfg(not(Py_3_11))] // moved to src/buffer.rs from 3.11
234extern "C" {
235    #[cfg_attr(PyPy, link_name = "PyPyObject_GetBuffer")]
236    pub fn PyObject_GetBuffer(obj: *mut PyObject, view: *mut Py_buffer, flags: c_int) -> c_int;
237    #[cfg_attr(PyPy, link_name = "PyPyBuffer_GetPointer")]
238    pub fn PyBuffer_GetPointer(
239        view: *mut Py_buffer,
240        indices: *mut Py_ssize_t,
241    ) -> *mut std::os::raw::c_void;
242    #[cfg_attr(PyPy, link_name = "PyPyBuffer_SizeFromFormat")]
243    pub fn PyBuffer_SizeFromFormat(format: *const c_char) -> Py_ssize_t;
244    #[cfg_attr(PyPy, link_name = "PyPyBuffer_ToContiguous")]
245    pub fn PyBuffer_ToContiguous(
246        buf: *mut std::os::raw::c_void,
247        view: *mut Py_buffer,
248        len: Py_ssize_t,
249        order: c_char,
250    ) -> c_int;
251    #[cfg_attr(PyPy, link_name = "PyPyBuffer_FromContiguous")]
252    pub fn PyBuffer_FromContiguous(
253        view: *mut Py_buffer,
254        buf: *mut std::os::raw::c_void,
255        len: Py_ssize_t,
256        order: c_char,
257    ) -> c_int;
258    pub fn PyObject_CopyData(dest: *mut PyObject, src: *mut PyObject) -> c_int;
259    #[cfg_attr(PyPy, link_name = "PyPyBuffer_IsContiguous")]
260    pub fn PyBuffer_IsContiguous(view: *const Py_buffer, fort: c_char) -> c_int;
261    pub fn PyBuffer_FillContiguousStrides(
262        ndims: c_int,
263        shape: *mut Py_ssize_t,
264        strides: *mut Py_ssize_t,
265        itemsize: c_int,
266        fort: c_char,
267    );
268    #[cfg_attr(PyPy, link_name = "PyPyBuffer_FillInfo")]
269    pub fn PyBuffer_FillInfo(
270        view: *mut Py_buffer,
271        o: *mut PyObject,
272        buf: *mut std::os::raw::c_void,
273        len: Py_ssize_t,
274        readonly: c_int,
275        flags: c_int,
276    ) -> c_int;
277    #[cfg_attr(PyPy, link_name = "PyPyBuffer_Release")]
278    pub fn PyBuffer_Release(view: *mut Py_buffer);
279}
280
281// PyIter_Check defined in ffi/abstract_.rs
282// PyIndex_Check defined in ffi/abstract_.rs
283// Not defined here because this file is not compiled under the
284// limited API, but the macros need to be defined for 3.6, 3.7 which
285// predate the limited API changes.
286
287// skipped PySequence_ITEM
288
289pub const PY_ITERSEARCH_COUNT: c_int = 1;
290pub const PY_ITERSEARCH_INDEX: c_int = 2;
291pub const PY_ITERSEARCH_CONTAINS: c_int = 3;
292
293extern "C" {
294    #[cfg(not(any(PyPy, GraalPy)))]
295    pub fn _PySequence_IterSearch(
296        seq: *mut PyObject,
297        obj: *mut PyObject,
298        operation: c_int,
299    ) -> Py_ssize_t;
300}
301
302// skipped _PyObject_RealIsInstance
303// skipped _PyObject_RealIsSubclass
304
305// skipped _PySequence_BytesToCharpArray
306
307// skipped _Py_FreeCharPArray
308
309// skipped _Py_add_one_to_index_F
310// skipped _Py_add_one_to_index_C
311
312// skipped _Py_convert_optional_to_ssize_t
313
314// skipped _PyNumber_Index(*mut PyObject o)