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