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)]
45pub const 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))))]
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(all(PyPy, Py_3_8))]
107    #[cfg_attr(not(Py_3_9), link_name = "_PyPyObject_Vectorcall")]
108    #[cfg_attr(Py_3_9, link_name = "PyPyObject_Vectorcall")]
109    pub fn PyObject_Vectorcall(
110        callable: *mut PyObject,
111        args: *const *mut PyObject,
112        nargsf: size_t,
113        kwnames: *mut PyObject,
114    ) -> *mut PyObject;
115
116    #[cfg(Py_3_8)]
117    #[cfg_attr(
118        all(not(any(PyPy, GraalPy)), not(Py_3_9)),
119        link_name = "_PyObject_VectorcallDict"
120    )]
121    #[cfg_attr(all(PyPy, not(Py_3_9)), link_name = "_PyPyObject_VectorcallDict")]
122    #[cfg_attr(all(PyPy, Py_3_9), link_name = "PyPyObject_VectorcallDict")]
123    pub fn PyObject_VectorcallDict(
124        callable: *mut PyObject,
125        args: *const *mut PyObject,
126        nargsf: size_t,
127        kwdict: *mut PyObject,
128    ) -> *mut PyObject;
129
130    #[cfg(Py_3_8)]
131    #[cfg_attr(not(any(Py_3_9, PyPy)), link_name = "_PyVectorcall_Call")]
132    #[cfg_attr(PyPy, link_name = "PyPyVectorcall_Call")]
133    pub fn PyVectorcall_Call(
134        callable: *mut PyObject,
135        tuple: *mut PyObject,
136        dict: *mut PyObject,
137    ) -> *mut PyObject;
138}
139
140#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
141#[inline(always)]
142pub unsafe fn _PyObject_FastCallTstate(
143    tstate: *mut PyThreadState,
144    func: *mut PyObject,
145    args: *const *mut PyObject,
146    nargs: Py_ssize_t,
147) -> *mut PyObject {
148    _PyObject_VectorcallTstate(tstate, func, args, nargs as size_t, std::ptr::null_mut())
149}
150
151#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
152#[inline(always)]
153pub unsafe fn _PyObject_FastCall(
154    func: *mut PyObject,
155    args: *const *mut PyObject,
156    nargs: Py_ssize_t,
157) -> *mut PyObject {
158    _PyObject_FastCallTstate(PyThreadState_GET(), func, args, nargs)
159}
160
161#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
162#[inline(always)]
163pub unsafe fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject {
164    _PyObject_VectorcallTstate(
165        PyThreadState_GET(),
166        func,
167        std::ptr::null_mut(),
168        0,
169        std::ptr::null_mut(),
170    )
171}
172
173extern "C" {
174    #[cfg(PyPy)]
175    #[link_name = "_PyPyObject_CallNoArg"]
176    pub fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject;
177}
178
179#[cfg(all(Py_3_8, not(any(PyPy, GraalPy))))]
180#[inline(always)]
181pub unsafe fn PyObject_CallOneArg(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject {
182    assert!(!arg.is_null());
183    let args_array = [std::ptr::null_mut(), arg];
184    let args = args_array.as_ptr().offset(1); // For PY_VECTORCALL_ARGUMENTS_OFFSET
185    let tstate = PyThreadState_GET();
186    let nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
187    _PyObject_VectorcallTstate(tstate, func, args, nargsf, std::ptr::null_mut())
188}
189
190extern "C" {
191    #[cfg(all(Py_3_9, not(any(PyPy, GraalPy))))]
192    pub fn PyObject_VectorcallMethod(
193        name: *mut PyObject,
194        args: *const *mut PyObject,
195        nargsf: size_t,
196        kwnames: *mut PyObject,
197    ) -> *mut PyObject;
198}
199
200#[cfg(all(Py_3_9, not(any(PyPy, GraalPy))))]
201#[inline(always)]
202pub unsafe fn PyObject_CallMethodNoArgs(
203    self_: *mut PyObject,
204    name: *mut PyObject,
205) -> *mut PyObject {
206    PyObject_VectorcallMethod(
207        name,
208        &self_,
209        1 | PY_VECTORCALL_ARGUMENTS_OFFSET,
210        std::ptr::null_mut(),
211    )
212}
213
214#[cfg(all(Py_3_9, not(any(PyPy, GraalPy))))]
215#[inline(always)]
216pub unsafe fn PyObject_CallMethodOneArg(
217    self_: *mut PyObject,
218    name: *mut PyObject,
219    arg: *mut PyObject,
220) -> *mut PyObject {
221    let args = [self_, arg];
222    assert!(!arg.is_null());
223    PyObject_VectorcallMethod(
224        name,
225        args.as_ptr(),
226        2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
227        std::ptr::null_mut(),
228    )
229}
230
231// skipped _PyObject_VectorcallMethodId
232// skipped _PyObject_CallMethodIdNoArgs
233// skipped _PyObject_CallMethodIdOneArg
234
235// skipped _PyObject_HasLen
236
237extern "C" {
238    #[cfg_attr(PyPy, link_name = "PyPyObject_LengthHint")]
239    pub fn PyObject_LengthHint(o: *mut PyObject, arg1: Py_ssize_t) -> Py_ssize_t;
240
241    #[cfg(not(Py_3_11))] // moved to src/buffer.rs from 3.11
242    #[cfg(all(Py_3_9, not(any(PyPy, GraalPy))))]
243    pub fn PyObject_CheckBuffer(obj: *mut PyObject) -> c_int;
244}
245
246#[cfg(not(any(Py_3_9, PyPy)))]
247#[inline]
248pub unsafe fn PyObject_CheckBuffer(o: *mut PyObject) -> c_int {
249    let tp_as_buffer = (*crate::Py_TYPE(o)).tp_as_buffer;
250    (!tp_as_buffer.is_null() && (*tp_as_buffer).bf_getbuffer.is_some()) as c_int
251}
252
253#[cfg(not(Py_3_11))] // moved to src/buffer.rs from 3.11
254extern "C" {
255    #[cfg_attr(PyPy, link_name = "PyPyObject_GetBuffer")]
256    pub fn PyObject_GetBuffer(obj: *mut PyObject, view: *mut Py_buffer, flags: c_int) -> c_int;
257    #[cfg_attr(PyPy, link_name = "PyPyBuffer_GetPointer")]
258    pub fn PyBuffer_GetPointer(
259        view: *mut Py_buffer,
260        indices: *mut Py_ssize_t,
261    ) -> *mut std::os::raw::c_void;
262    #[cfg_attr(PyPy, link_name = "PyPyBuffer_SizeFromFormat")]
263    pub fn PyBuffer_SizeFromFormat(format: *const c_char) -> Py_ssize_t;
264    #[cfg_attr(PyPy, link_name = "PyPyBuffer_ToContiguous")]
265    pub fn PyBuffer_ToContiguous(
266        buf: *mut std::os::raw::c_void,
267        view: *mut Py_buffer,
268        len: Py_ssize_t,
269        order: c_char,
270    ) -> c_int;
271    #[cfg_attr(PyPy, link_name = "PyPyBuffer_FromContiguous")]
272    pub fn PyBuffer_FromContiguous(
273        view: *mut Py_buffer,
274        buf: *mut std::os::raw::c_void,
275        len: Py_ssize_t,
276        order: c_char,
277    ) -> c_int;
278    pub fn PyObject_CopyData(dest: *mut PyObject, src: *mut PyObject) -> c_int;
279    #[cfg_attr(PyPy, link_name = "PyPyBuffer_IsContiguous")]
280    pub fn PyBuffer_IsContiguous(view: *const Py_buffer, fort: c_char) -> c_int;
281    pub fn PyBuffer_FillContiguousStrides(
282        ndims: c_int,
283        shape: *mut Py_ssize_t,
284        strides: *mut Py_ssize_t,
285        itemsize: c_int,
286        fort: c_char,
287    );
288    #[cfg_attr(PyPy, link_name = "PyPyBuffer_FillInfo")]
289    pub fn PyBuffer_FillInfo(
290        view: *mut Py_buffer,
291        o: *mut PyObject,
292        buf: *mut std::os::raw::c_void,
293        len: Py_ssize_t,
294        readonly: c_int,
295        flags: c_int,
296    ) -> c_int;
297    #[cfg_attr(PyPy, link_name = "PyPyBuffer_Release")]
298    pub fn PyBuffer_Release(view: *mut Py_buffer);
299}
300
301// PyIter_Check defined in ffi/abstract_.rs
302// PyIndex_Check defined in ffi/abstract_.rs
303// Not defined here because this file is not compiled under the
304// limited API, but the macros need to be defined for 3.6, 3.7 which
305// predate the limited API changes.
306
307// skipped PySequence_ITEM
308
309pub const PY_ITERSEARCH_COUNT: c_int = 1;
310pub const PY_ITERSEARCH_INDEX: c_int = 2;
311pub const PY_ITERSEARCH_CONTAINS: c_int = 3;
312
313extern "C" {
314    #[cfg(not(any(PyPy, GraalPy)))]
315    pub fn _PySequence_IterSearch(
316        seq: *mut PyObject,
317        obj: *mut PyObject,
318        operation: c_int,
319    ) -> Py_ssize_t;
320}
321
322// skipped _PyObject_RealIsInstance
323// skipped _PyObject_RealIsSubclass
324
325// skipped _PySequence_BytesToCharpArray
326
327// skipped _Py_FreeCharPArray
328
329// skipped _Py_add_one_to_index_F
330// skipped _Py_add_one_to_index_C
331
332// skipped _Py_convert_optional_to_ssize_t
333
334// skipped _PyNumber_Index(*mut PyObject o)