Skip to main content

pyforge_ffi/cpython/
abstract_.rs

1use crate::{PyObject, Py_ssize_t};
2use std::ffi::c_char;
3use std::ffi::c_int;
4
5use crate::{
6    vectorcallfunc, PyCallable_Check, PyThreadState, PyThreadState_GET, PyTuple_Check,
7    PyType_HasFeature, Py_TPFLAGS_HAVE_VECTORCALL,
8};
9use libc::size_t;
10
11extern_libpython! {
12    pub fn _PyStack_AsDict(values: *const *mut PyObject, kwnames: *mut PyObject) -> *mut PyObject;
13}
14
15const _PY_FASTCALL_SMALL_STACK: size_t = 5;
16
17extern_libpython! {
18    pub fn _Py_CheckFunctionResult(
19        tstate: *mut PyThreadState,
20        callable: *mut PyObject,
21        result: *mut PyObject,
22        where_: *const c_char,
23    ) -> *mut PyObject;
24
25    pub fn _PyObject_MakeTpCall(
26        tstate: *mut PyThreadState,
27        callable: *mut PyObject,
28        args: *const *mut PyObject,
29        nargs: Py_ssize_t,
30        keywords: *mut PyObject,
31    ) -> *mut PyObject;
32}
33
34const PY_VECTORCALL_ARGUMENTS_OFFSET: size_t =
35    1 << (8 * std::mem::size_of::<size_t>() as size_t - 1);
36
37#[inline(always)]
38pub unsafe fn PyVectorcall_NARGS(n: size_t) -> Py_ssize_t {
39    let n = n & !PY_VECTORCALL_ARGUMENTS_OFFSET;
40    n.try_into().expect("cannot fail due to mask")
41}
42
43#[inline(always)]
44pub unsafe fn PyVectorcall_Function(callable: *mut PyObject) -> Option<vectorcallfunc> {
45    assert!(!callable.is_null());
46    let tp = crate::Py_TYPE(callable);
47    if PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL) == 0 {
48        return None;
49    }
50    assert!(PyCallable_Check(callable) > 0);
51    let offset = (*tp).tp_vectorcall_offset;
52    assert!(offset > 0);
53    let ptr = callable.cast::<c_char>().offset(offset).cast();
54    *ptr
55}
56
57#[inline(always)]
58pub unsafe fn _PyObject_VectorcallTstate(
59    tstate: *mut PyThreadState,
60    callable: *mut PyObject,
61    args: *const *mut PyObject,
62    nargsf: size_t,
63    kwnames: *mut PyObject,
64) -> *mut PyObject {
65    assert!(kwnames.is_null() || PyTuple_Check(kwnames) > 0);
66    assert!(!args.is_null() || PyVectorcall_NARGS(nargsf) == 0);
67
68    match PyVectorcall_Function(callable) {
69        None => {
70            let nargs = PyVectorcall_NARGS(nargsf);
71            _PyObject_MakeTpCall(tstate, callable, args, nargs, kwnames)
72        }
73        Some(func) => {
74            let res = func(callable, args, nargsf, kwnames);
75            _Py_CheckFunctionResult(tstate, callable, res, std::ptr::null_mut())
76        }
77    }
78}
79
80extern_libpython! {
81    pub fn PyObject_VectorcallDict(
82        callable: *mut PyObject,
83        args: *const *mut PyObject,
84        nargsf: size_t,
85        kwdict: *mut PyObject,
86    ) -> *mut PyObject;
87
88    pub fn PyVectorcall_Call(
89        callable: *mut PyObject,
90        tuple: *mut PyObject,
91        dict: *mut PyObject,
92    ) -> *mut PyObject;
93}
94
95#[inline(always)]
96pub unsafe fn _PyObject_FastCallTstate(
97    tstate: *mut PyThreadState,
98    func: *mut PyObject,
99    args: *const *mut PyObject,
100    nargs: Py_ssize_t,
101) -> *mut PyObject {
102    _PyObject_VectorcallTstate(tstate, func, args, nargs as size_t, std::ptr::null_mut())
103}
104
105#[inline(always)]
106pub unsafe fn _PyObject_FastCall(
107    func: *mut PyObject,
108    args: *const *mut PyObject,
109    nargs: Py_ssize_t,
110) -> *mut PyObject {
111    _PyObject_FastCallTstate(PyThreadState_GET(), func, args, nargs)
112}
113
114#[inline(always)]
115pub unsafe fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject {
116    _PyObject_VectorcallTstate(
117        PyThreadState_GET(),
118        func,
119        std::ptr::null_mut(),
120        0,
121        std::ptr::null_mut(),
122    )
123}
124
125#[inline(always)]
126pub unsafe fn PyObject_CallOneArg(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject {
127    assert!(!arg.is_null());
128    let args_array = [std::ptr::null_mut(), arg];
129    let args = args_array.as_ptr().offset(1); // For PY_VECTORCALL_ARGUMENTS_OFFSET
130    let tstate = PyThreadState_GET();
131    let nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
132    _PyObject_VectorcallTstate(tstate, func, args, nargsf, std::ptr::null_mut())
133}
134
135#[inline(always)]
136pub unsafe fn PyObject_CallMethodNoArgs(
137    self_: *mut PyObject,
138    name: *mut PyObject,
139) -> *mut PyObject {
140    crate::PyObject_VectorcallMethod(
141        name,
142        &self_,
143        1 | PY_VECTORCALL_ARGUMENTS_OFFSET,
144        std::ptr::null_mut(),
145    )
146}
147
148#[inline(always)]
149pub unsafe fn PyObject_CallMethodOneArg(
150    self_: *mut PyObject,
151    name: *mut PyObject,
152    arg: *mut PyObject,
153) -> *mut PyObject {
154    let args = [self_, arg];
155    assert!(!arg.is_null());
156    crate::PyObject_VectorcallMethod(
157        name,
158        args.as_ptr(),
159        2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
160        std::ptr::null_mut(),
161    )
162}
163
164// skipped _PyObject_VectorcallMethodId
165// skipped _PyObject_CallMethodIdNoArgs
166// skipped _PyObject_CallMethodIdOneArg
167
168// skipped _PyObject_HasLen
169
170extern_libpython! {
171    pub fn PyObject_LengthHint(o: *mut PyObject, arg1: Py_ssize_t) -> Py_ssize_t;
172
173}
174
175// skipped PySequence_ITEM
176
177pub const PY_ITERSEARCH_COUNT: c_int = 1;
178pub const PY_ITERSEARCH_INDEX: c_int = 2;
179pub const PY_ITERSEARCH_CONTAINS: c_int = 3;
180
181extern_libpython! {
182    pub fn _PySequence_IterSearch(
183        seq: *mut PyObject,
184        obj: *mut PyObject,
185        operation: c_int,
186    ) -> Py_ssize_t;
187}
188
189// skipped _PyObject_RealIsInstance
190// skipped _PyObject_RealIsSubclass
191
192// skipped _PySequence_BytesToCharpArray
193
194// skipped _Py_FreeCharPArray
195
196// skipped _Py_add_one_to_index_F
197// skipped _Py_add_one_to_index_C
198
199// skipped _Py_convert_optional_to_ssize_t
200
201// skipped _PyNumber_Index(*mut PyObject o)