pyforge_ffi/cpython/
abstract_.rs1use 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); 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
164extern_libpython! {
171 pub fn PyObject_LengthHint(o: *mut PyObject, arg1: Py_ssize_t) -> Py_ssize_t;
172
173}
174
175pub 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