1 | use crate::object::{PyObject, PyTypeObject, Py_TYPE}; |
2 | #[cfg (Py_3_9)] |
3 | use crate::PyObject_TypeCheck; |
4 | use std::os::raw::{c_char, c_int, c_void}; |
5 | use std::{mem, ptr}; |
6 | |
7 | #[cfg (all(Py_3_9, not(Py_LIMITED_API), not(GraalPy)))] |
8 | pub struct PyCFunctionObject { |
9 | pub ob_base: PyObject, |
10 | pub m_ml: *mut PyMethodDef, |
11 | pub m_self: *mut PyObject, |
12 | pub m_module: *mut PyObject, |
13 | pub m_weakreflist: *mut PyObject, |
14 | #[cfg (not(PyPy))] |
15 | pub vectorcall: Option<crate::vectorcallfunc>, |
16 | } |
17 | |
18 | #[cfg_attr (windows, link(name = "pythonXY" ))] |
19 | unsafeextern "C" { |
20 | #[cfg_attr (PyPy, link_name = "PyPyCFunction_Type" )] |
21 | pub unsafestatic mut PyCFunction_Type: PyTypeObject; |
22 | } |
23 | |
24 | #[cfg (Py_3_9)] |
25 | #[inline ] |
26 | pub unsafe fn PyCFunction_CheckExact(op: *mut PyObject) -> c_int { |
27 | (Py_TYPE(ob:op) == ptr::addr_of_mut!(PyCFunction_Type)) as c_int |
28 | } |
29 | |
30 | #[cfg (Py_3_9)] |
31 | #[inline ] |
32 | pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { |
33 | PyObject_TypeCheck(ob:op, tp:ptr::addr_of_mut!(PyCFunction_Type)) |
34 | } |
35 | |
36 | #[cfg (not(Py_3_9))] |
37 | #[inline ] |
38 | pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int { |
39 | (Py_TYPE(op) == ptr::addr_of_mut!(PyCFunction_Type)) as c_int |
40 | } |
41 | |
42 | pub type PyCFunction = |
43 | unsafe extern "C" fn(slf: *mut PyObject, args: *mut PyObject) -> *mut PyObject; |
44 | |
45 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
46 | pub type PyCFunctionFast = unsafe extern "C" fn( |
47 | slf: *mut PyObject, |
48 | args: *mut *mut PyObject, |
49 | nargs: crate::pyport::Py_ssize_t, |
50 | ) -> *mut PyObject; |
51 | |
52 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
53 | #[deprecated (note = "renamed to `PyCFunctionFast`" )] |
54 | pub type _PyCFunctionFast = PyCFunctionFast; |
55 | |
56 | pub type PyCFunctionWithKeywords = unsafe extern "C" fn( |
57 | slf: *mut PyObject, |
58 | args: *mut PyObject, |
59 | kwds: *mut PyObject, |
60 | ) -> *mut PyObject; |
61 | |
62 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
63 | pub type PyCFunctionFastWithKeywords = unsafe extern "C" fn( |
64 | slf: *mut PyObject, |
65 | args: *const *mut PyObject, |
66 | nargs: crate::pyport::Py_ssize_t, |
67 | kwnames: *mut PyObject, |
68 | ) -> *mut PyObject; |
69 | |
70 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
71 | #[deprecated (note = "renamed to `PyCFunctionFastWithKeywords`" )] |
72 | pub type _PyCFunctionFastWithKeywords = PyCFunctionFastWithKeywords; |
73 | |
74 | #[cfg (all(Py_3_9, not(Py_LIMITED_API)))] |
75 | pub type PyCMethod = unsafe extern "C" fn( |
76 | slf: *mut PyObject, |
77 | defining_class: *mut PyTypeObject, |
78 | args: *const *mut PyObject, |
79 | nargs: crate::pyport::Py_ssize_t, |
80 | kwnames: *mut PyObject, |
81 | ) -> *mut PyObject; |
82 | |
83 | unsafeextern "C" { |
84 | #[cfg_attr (PyPy, link_name = "PyPyCFunction_GetFunction" )] |
85 | pub unsafefn PyCFunction_GetFunction(f: *mut PyObject) -> Option<PyCFunction>; |
86 | pub unsafefn PyCFunction_GetSelf(f: *mut PyObject) -> *mut PyObject; |
87 | pub unsafefn PyCFunction_GetFlags(f: *mut PyObject) -> c_int; |
88 | #[cfg (not(Py_3_13))] |
89 | #[cfg_attr (Py_3_9, deprecated(note = "Python 3.9" ))] |
90 | pub unsafefn PyCFunction_Call( |
91 | f: *mut PyObject, |
92 | args: *mut PyObject, |
93 | kwds: *mut PyObject, |
94 | ) -> *mut PyObject; |
95 | } |
96 | |
97 | /// Represents the [PyMethodDef](https://docs.python.org/3/c-api/structures.html#c.PyMethodDef) |
98 | /// structure. |
99 | /// |
100 | /// Note that CPython may leave fields uninitialized. You must ensure that |
101 | /// `ml_name` != NULL before dereferencing or reading other fields. |
102 | #[repr (C)] |
103 | #[derive (Copy, Clone, PartialEq, Eq)] |
104 | pub struct PyMethodDef { |
105 | pub ml_name: *const c_char, |
106 | pub ml_meth: PyMethodDefPointer, |
107 | pub ml_flags: c_int, |
108 | pub ml_doc: *const c_char, |
109 | } |
110 | |
111 | impl PyMethodDef { |
112 | pub const fn zeroed() -> PyMethodDef { |
113 | PyMethodDef { |
114 | ml_name: ptr::null(), |
115 | ml_meth: PyMethodDefPointer { |
116 | Void: ptr::null_mut(), |
117 | }, |
118 | ml_flags: 0, |
119 | ml_doc: ptr::null(), |
120 | } |
121 | } |
122 | } |
123 | |
124 | impl Default for PyMethodDef { |
125 | fn default() -> PyMethodDef { |
126 | PyMethodDef { |
127 | ml_name: ptr::null(), |
128 | ml_meth: PyMethodDefPointer { |
129 | Void: ptr::null_mut(), |
130 | }, |
131 | ml_flags: 0, |
132 | ml_doc: ptr::null(), |
133 | } |
134 | } |
135 | } |
136 | |
137 | /// Function types used to implement Python callables. |
138 | /// |
139 | /// This function pointer must be accompanied by the correct [ml_flags](PyMethodDef::ml_flags), |
140 | /// otherwise the behavior is undefined. |
141 | /// |
142 | /// See the [Python C API documentation][1] for more information. |
143 | /// |
144 | /// [1]: https://docs.python.org/3/c-api/structures.html#implementing-functions-and-methods |
145 | #[repr (C)] |
146 | #[derive (Copy, Clone, Eq)] |
147 | pub union PyMethodDefPointer { |
148 | /// This variant corresponds with [`METH_VARARGS`] *or* [`METH_NOARGS`] *or* [`METH_O`]. |
149 | pub PyCFunction: PyCFunction, |
150 | |
151 | /// This variant corresponds with [`METH_VARARGS`] | [`METH_KEYWORDS`]. |
152 | pub PyCFunctionWithKeywords: PyCFunctionWithKeywords, |
153 | |
154 | /// This variant corresponds with [`METH_FASTCALL`]. |
155 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
156 | #[deprecated (note = "renamed to `PyCFunctionFast`" )] |
157 | pub _PyCFunctionFast: PyCFunctionFast, |
158 | |
159 | /// This variant corresponds with [`METH_FASTCALL`]. |
160 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
161 | pub PyCFunctionFast: PyCFunctionFast, |
162 | |
163 | /// This variant corresponds with [`METH_FASTCALL`] | [`METH_KEYWORDS`]. |
164 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
165 | #[deprecated (note = "renamed to `PyCFunctionFastWithKeywords`" )] |
166 | pub _PyCFunctionFastWithKeywords: PyCFunctionFastWithKeywords, |
167 | |
168 | /// This variant corresponds with [`METH_FASTCALL`] | [`METH_KEYWORDS`]. |
169 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
170 | pub PyCFunctionFastWithKeywords: PyCFunctionFastWithKeywords, |
171 | |
172 | /// This variant corresponds with [`METH_METHOD`] | [`METH_FASTCALL`] | [`METH_KEYWORDS`]. |
173 | #[cfg (all(Py_3_9, not(Py_LIMITED_API)))] |
174 | pub PyCMethod: PyCMethod, |
175 | |
176 | Void: *mut c_void, |
177 | } |
178 | |
179 | impl PyMethodDefPointer { |
180 | pub fn as_ptr(&self) -> *mut c_void { |
181 | unsafe { self.Void } |
182 | } |
183 | |
184 | pub fn is_null(&self) -> bool { |
185 | self.as_ptr().is_null() |
186 | } |
187 | |
188 | pub const fn zeroed() -> PyMethodDefPointer { |
189 | PyMethodDefPointer { |
190 | Void: ptr::null_mut(), |
191 | } |
192 | } |
193 | } |
194 | |
195 | impl PartialEq for PyMethodDefPointer { |
196 | fn eq(&self, other: &Self) -> bool { |
197 | unsafe { self.Void == other.Void } |
198 | } |
199 | } |
200 | |
201 | impl std::fmt::Pointer for PyMethodDefPointer { |
202 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
203 | let ptr: *mut c_void = unsafe { self.Void }; |
204 | std::fmt::Pointer::fmt(&ptr, f) |
205 | } |
206 | } |
207 | |
208 | const _: () = |
209 | assert!(mem::size_of::<PyMethodDefPointer>() == mem::size_of::<Option<extern "C" fn()>>()); |
210 | |
211 | #[cfg (not(Py_3_9))] |
212 | extern "C" { |
213 | #[cfg_attr (PyPy, link_name = "PyPyCFunction_New" )] |
214 | pub fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject; |
215 | |
216 | #[cfg_attr (PyPy, link_name = "PyPyCFunction_NewEx" )] |
217 | pub fn PyCFunction_NewEx( |
218 | ml: *mut PyMethodDef, |
219 | slf: *mut PyObject, |
220 | module: *mut PyObject, |
221 | ) -> *mut PyObject; |
222 | } |
223 | |
224 | #[cfg (Py_3_9)] |
225 | #[inline ] |
226 | pub unsafe fn PyCFunction_New(ml: *mut PyMethodDef, slf: *mut PyObject) -> *mut PyObject { |
227 | PyCFunction_NewEx(ml, slf, module:std::ptr::null_mut()) |
228 | } |
229 | |
230 | #[cfg (Py_3_9)] |
231 | #[inline ] |
232 | pub unsafe fn PyCFunction_NewEx( |
233 | ml: *mut PyMethodDef, |
234 | slf: *mut PyObject, |
235 | module: *mut PyObject, |
236 | ) -> *mut PyObject { |
237 | PyCMethod_New(ml, slf, module, cls:std::ptr::null_mut()) |
238 | } |
239 | |
240 | #[cfg (Py_3_9)] |
241 | unsafeextern "C" { |
242 | #[cfg_attr (PyPy, link_name = "PyPyCMethod_New" )] |
243 | pub unsafefn PyCMethod_New( |
244 | ml: *mut PyMethodDef, |
245 | slf: *mut PyObject, |
246 | module: *mut PyObject, |
247 | cls: *mut PyTypeObject, |
248 | ) -> *mut PyObject; |
249 | } |
250 | |
251 | /* Flag passed to newmethodobject */ |
252 | pub const METH_VARARGS: c_int = 0x0001; |
253 | pub const METH_KEYWORDS: c_int = 0x0002; |
254 | /* METH_NOARGS and METH_O must not be combined with the flags above. */ |
255 | pub const METH_NOARGS: c_int = 0x0004; |
256 | pub const METH_O: c_int = 0x0008; |
257 | |
258 | /* METH_CLASS and METH_STATIC are a little different; these control |
259 | the construction of methods for a class. These cannot be used for |
260 | functions in modules. */ |
261 | pub const METH_CLASS: c_int = 0x0010; |
262 | pub const METH_STATIC: c_int = 0x0020; |
263 | |
264 | /* METH_COEXIST allows a method to be entered eventhough a slot has |
265 | already filled the entry. When defined, the flag allows a separate |
266 | method, "__contains__" for example, to coexist with a defined |
267 | slot like sq_contains. */ |
268 | |
269 | pub const METH_COEXIST: c_int = 0x0040; |
270 | |
271 | /* METH_FASTCALL indicates the PEP 590 Vectorcall calling format. It may |
272 | be specified alone or with METH_KEYWORDS. */ |
273 | #[cfg (any(Py_3_10, not(Py_LIMITED_API)))] |
274 | pub const METH_FASTCALL: c_int = 0x0080; |
275 | |
276 | // skipped METH_STACKLESS |
277 | |
278 | #[cfg (all(Py_3_9, not(Py_LIMITED_API)))] |
279 | pub const METH_METHOD: c_int = 0x0200; |
280 | |
281 | unsafeextern "C" { |
282 | #[cfg (not(Py_3_9))] |
283 | pub fn PyCFunction_ClearFreeList() -> c_int; |
284 | } |
285 | |