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