pyo3_ffi/cpython/
abstract_.rs

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