1use crate::{
2 ffi,
3 types::{PyType, PyTypeMethods},
4 Borrowed, Bound,
5};
6use std::os::raw::c_int;
7
8impl Bound<'_, PyType> {
9 #[inline]
10 pub(crate) fn get_slot<const S: c_int>(&self, slot: Slot<S>) -> <Slot<S> as GetSlotImpl>::Type
11 where
12 Slot<S>: GetSlotImpl,
13 {
14 unsafe {
16 slot.get_slot(
17 self.as_type_ptr(),
18 #[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
19 is_runtime_3_10(self.py()),
20 )
21 }
22 }
23}
24
25impl Borrowed<'_, '_, PyType> {
26 #[inline]
27 pub(crate) fn get_slot<const S: c_int>(self, slot: Slot<S>) -> <Slot<S> as GetSlotImpl>::Type
28 where
29 Slot<S>: GetSlotImpl,
30 {
31 unsafe {
33 slot.get_slot(
34 self.as_type_ptr(),
35 #[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
36 is_runtime_3_10(self.py()),
37 )
38 }
39 }
40}
41
42pub(crate) unsafe fn get_slot<const S: c_int>(
48 ty: *mut ffi::PyTypeObject,
49 slot: Slot<S>,
50) -> <Slot<S> as GetSlotImpl>::Type
51where
52 Slot<S>: GetSlotImpl,
53{
54 unsafe {
55 slot.get_slot(
56 ty,
57 #[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
59 is_runtime_3_10(crate::Python::assume_gil_acquired()),
60 )
61 }
62}
63
64pub(crate) trait GetSlotImpl {
65 type Type;
66
67 unsafe fn get_slot(
73 self,
74 ty: *mut ffi::PyTypeObject,
75 #[cfg(all(Py_LIMITED_API, not(Py_3_10)))] is_runtime_3_10: bool,
76 ) -> Self::Type;
77}
78
79#[derive(Copy, Clone)]
80pub(crate) struct Slot<const S: c_int>;
81
82macro_rules! impl_slots {
83 ($($name:ident: ($slot:ident, $field:ident) -> $tp:ty),+ $(,)?) => {
84 $(
85 pub (crate) const $name: Slot<{ ffi::$slot }> = Slot;
86
87 impl GetSlotImpl for Slot<{ ffi::$slot }> {
88 type Type = $tp;
89
90 #[inline]
91 unsafe fn get_slot(
92 self,
93 ty: *mut ffi::PyTypeObject,
94 #[cfg(all(Py_LIMITED_API, not(Py_3_10)))] is_runtime_3_10: bool
95 ) -> Self::Type {
96 #[cfg(not(Py_LIMITED_API))]
97 {
98 unsafe {(*ty).$field }
99 }
100
101 #[cfg(Py_LIMITED_API)]
102 {
103 #[cfg(not(Py_3_10))]
104 {
105 if !is_runtime_3_10 && unsafe {ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE)} == 0
111 {
112 return unsafe {(*ty.cast::<PyTypeObject39Snapshot>()).$field};
113 }
114 }
115
116 unsafe {std::mem::transmute(ffi::PyType_GetSlot(ty, ffi::$slot))}
118 }
119 }
120 }
121 )*
122 };
123}
124
125impl_slots! {
127 TP_ALLOC: (Py_tp_alloc, tp_alloc) -> Option<ffi::allocfunc>,
128 TP_BASE: (Py_tp_base, tp_base) -> *mut ffi::PyTypeObject,
129 TP_CLEAR: (Py_tp_clear, tp_clear) -> Option<ffi::inquiry>,
130 TP_DESCR_GET: (Py_tp_descr_get, tp_descr_get) -> Option<ffi::descrgetfunc>,
131 TP_FREE: (Py_tp_free, tp_free) -> Option<ffi::freefunc>,
132 TP_TRAVERSE: (Py_tp_traverse, tp_traverse) -> Option<ffi::traverseproc>,
133}
134
135#[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
136fn is_runtime_3_10(py: crate::Python<'_>) -> bool {
137 use crate::sync::GILOnceCell;
138
139 static IS_RUNTIME_3_10: GILOnceCell<bool> = GILOnceCell::new();
140 *IS_RUNTIME_3_10.get_or_init(py, || py.version_info() >= (3, 10))
141}
142
143#[repr(C)]
144#[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
145pub struct PyNumberMethods39Snapshot {
146 pub nb_add: Option<ffi::binaryfunc>,
147 pub nb_subtract: Option<ffi::binaryfunc>,
148 pub nb_multiply: Option<ffi::binaryfunc>,
149 pub nb_remainder: Option<ffi::binaryfunc>,
150 pub nb_divmod: Option<ffi::binaryfunc>,
151 pub nb_power: Option<ffi::ternaryfunc>,
152 pub nb_negative: Option<ffi::unaryfunc>,
153 pub nb_positive: Option<ffi::unaryfunc>,
154 pub nb_absolute: Option<ffi::unaryfunc>,
155 pub nb_bool: Option<ffi::inquiry>,
156 pub nb_invert: Option<ffi::unaryfunc>,
157 pub nb_lshift: Option<ffi::binaryfunc>,
158 pub nb_rshift: Option<ffi::binaryfunc>,
159 pub nb_and: Option<ffi::binaryfunc>,
160 pub nb_xor: Option<ffi::binaryfunc>,
161 pub nb_or: Option<ffi::binaryfunc>,
162 pub nb_int: Option<ffi::unaryfunc>,
163 pub nb_reserved: *mut std::os::raw::c_void,
164 pub nb_float: Option<ffi::unaryfunc>,
165 pub nb_inplace_add: Option<ffi::binaryfunc>,
166 pub nb_inplace_subtract: Option<ffi::binaryfunc>,
167 pub nb_inplace_multiply: Option<ffi::binaryfunc>,
168 pub nb_inplace_remainder: Option<ffi::binaryfunc>,
169 pub nb_inplace_power: Option<ffi::ternaryfunc>,
170 pub nb_inplace_lshift: Option<ffi::binaryfunc>,
171 pub nb_inplace_rshift: Option<ffi::binaryfunc>,
172 pub nb_inplace_and: Option<ffi::binaryfunc>,
173 pub nb_inplace_xor: Option<ffi::binaryfunc>,
174 pub nb_inplace_or: Option<ffi::binaryfunc>,
175 pub nb_floor_divide: Option<ffi::binaryfunc>,
176 pub nb_true_divide: Option<ffi::binaryfunc>,
177 pub nb_inplace_floor_divide: Option<ffi::binaryfunc>,
178 pub nb_inplace_true_divide: Option<ffi::binaryfunc>,
179 pub nb_index: Option<ffi::unaryfunc>,
180 pub nb_matrix_multiply: Option<ffi::binaryfunc>,
181 pub nb_inplace_matrix_multiply: Option<ffi::binaryfunc>,
182}
183
184#[repr(C)]
185#[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
186pub struct PySequenceMethods39Snapshot {
187 pub sq_length: Option<ffi::lenfunc>,
188 pub sq_concat: Option<ffi::binaryfunc>,
189 pub sq_repeat: Option<ffi::ssizeargfunc>,
190 pub sq_item: Option<ffi::ssizeargfunc>,
191 pub was_sq_slice: *mut std::os::raw::c_void,
192 pub sq_ass_item: Option<ffi::ssizeobjargproc>,
193 pub was_sq_ass_slice: *mut std::os::raw::c_void,
194 pub sq_contains: Option<ffi::objobjproc>,
195 pub sq_inplace_concat: Option<ffi::binaryfunc>,
196 pub sq_inplace_repeat: Option<ffi::ssizeargfunc>,
197}
198
199#[repr(C)]
200#[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
201pub struct PyMappingMethods39Snapshot {
202 pub mp_length: Option<ffi::lenfunc>,
203 pub mp_subscript: Option<ffi::binaryfunc>,
204 pub mp_ass_subscript: Option<ffi::objobjargproc>,
205}
206
207#[repr(C)]
208#[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
209pub struct PyAsyncMethods39Snapshot {
210 pub am_await: Option<ffi::unaryfunc>,
211 pub am_aiter: Option<ffi::unaryfunc>,
212 pub am_anext: Option<ffi::unaryfunc>,
213}
214
215#[repr(C)]
216#[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
217pub struct PyBufferProcs39Snapshot {
218 pub bf_getbuffer: *mut std::os::raw::c_void,
220 pub bf_releasebuffer: *mut std::os::raw::c_void,
221}
222
223#[repr(C)]
229#[cfg(all(Py_LIMITED_API, not(Py_3_10)))]
230struct PyTypeObject39Snapshot {
231 pub ob_base: ffi::PyVarObject,
232 pub tp_name: *const std::os::raw::c_char,
233 pub tp_basicsize: ffi::Py_ssize_t,
234 pub tp_itemsize: ffi::Py_ssize_t,
235 pub tp_dealloc: Option<ffi::destructor>,
236 #[cfg(not(Py_3_8))]
237 pub tp_print: *mut std::os::raw::c_void, #[cfg(Py_3_8)]
239 pub tp_vectorcall_offset: ffi::Py_ssize_t,
240 pub tp_getattr: Option<ffi::getattrfunc>,
241 pub tp_setattr: Option<ffi::setattrfunc>,
242 pub tp_as_async: *mut PyAsyncMethods39Snapshot,
243 pub tp_repr: Option<ffi::reprfunc>,
244 pub tp_as_number: *mut PyNumberMethods39Snapshot,
245 pub tp_as_sequence: *mut PySequenceMethods39Snapshot,
246 pub tp_as_mapping: *mut PyMappingMethods39Snapshot,
247 pub tp_hash: Option<ffi::hashfunc>,
248 pub tp_call: Option<ffi::ternaryfunc>,
249 pub tp_str: Option<ffi::reprfunc>,
250 pub tp_getattro: Option<ffi::getattrofunc>,
251 pub tp_setattro: Option<ffi::setattrofunc>,
252 pub tp_as_buffer: *mut PyBufferProcs39Snapshot,
253 pub tp_flags: std::os::raw::c_ulong,
254 pub tp_doc: *const std::os::raw::c_char,
255 pub tp_traverse: Option<ffi::traverseproc>,
256 pub tp_clear: Option<ffi::inquiry>,
257 pub tp_richcompare: Option<ffi::richcmpfunc>,
258 pub tp_weaklistoffset: ffi::Py_ssize_t,
259 pub tp_iter: Option<ffi::getiterfunc>,
260 pub tp_iternext: Option<ffi::iternextfunc>,
261 pub tp_methods: *mut ffi::PyMethodDef,
262 pub tp_members: *mut ffi::PyMemberDef,
263 pub tp_getset: *mut ffi::PyGetSetDef,
264 pub tp_base: *mut ffi::PyTypeObject,
265 pub tp_dict: *mut ffi::PyObject,
266 pub tp_descr_get: Option<ffi::descrgetfunc>,
267 pub tp_descr_set: Option<ffi::descrsetfunc>,
268 pub tp_dictoffset: ffi::Py_ssize_t,
269 pub tp_init: Option<ffi::initproc>,
270 pub tp_alloc: Option<ffi::allocfunc>,
271 pub tp_new: Option<ffi::newfunc>,
272 pub tp_free: Option<ffi::freefunc>,
273 pub tp_is_gc: Option<ffi::inquiry>,
274 pub tp_bases: *mut ffi::PyObject,
275 pub tp_mro: *mut ffi::PyObject,
276 pub tp_cache: *mut ffi::PyObject,
277 pub tp_subclasses: *mut ffi::PyObject,
278 pub tp_weaklist: *mut ffi::PyObject,
279 pub tp_del: Option<ffi::destructor>,
280 pub tp_version_tag: std::os::raw::c_uint,
281 pub tp_finalize: Option<ffi::destructor>,
282 #[cfg(Py_3_8)]
283 pub tp_vectorcall: Option<ffi::vectorcallfunc>,
284}