| 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 | |