Skip to main content

pyo3_ffi/
slots.rs

1#[cfg(Py_3_15)]
2use crate::Py_ssize_t;
3#[cfg(Py_3_15)]
4use core::ffi::{c_int, c_void};
5
6#[cfg(Py_3_15)]
7pub type _Py_funcptr_t = unsafe extern "C" fn();
8
9#[derive(Copy, Clone)]
10#[repr(C)]
11#[cfg(Py_3_15)]
12pub union _anon_union_32b {
13    pub sl_reserved: u32,
14}
15
16#[derive(Copy, Clone)]
17#[repr(C)]
18#[cfg(Py_3_15)]
19pub union _anon_union_64b {
20    pub sl_ptr: *mut c_void,
21    pub sl_func: Option<_Py_funcptr_t>,
22    pub sl_size: Py_ssize_t,
23    pub sl_int64: i64,
24    pub sl_uint64: u64,
25}
26
27#[derive(Copy, Clone)]
28#[repr(C)]
29#[cfg(Py_3_15)]
30pub struct PySlot {
31    pub sl_id: u16,
32    pub sl_flags: u16,
33    pub anon1: _anon_union_32b,
34    pub anon2: _anon_union_64b,
35}
36
37#[cfg(Py_3_15)]
38pub const PySlot_OPTIONAL: u16 = 0x01;
39#[cfg(Py_3_15)]
40pub const PySlot_STATIC: u16 = 0x02;
41#[cfg(Py_3_15)]
42pub const PySlot_INTPTR: u16 = 0x04;
43#[cfg(Py_3_15)]
44pub const Py_slot_invalid: u16 = 0xffff;
45
46// The slot IDs are integer constants in the C headers and don't have
47// explicit types. Legacy slot IDs are c integers but PySlot IDs are
48// u16s. We use this to convert from c_int to u16 safely, without using
49// `as`. The panic should only be possible if there is a programming
50// error somewhere leading to a slot ID outside the range of u16. If
51// TryInto becomes possible in const contexts we could use that instead.
52#[cfg(Py_3_15)]
53const fn safe_cast_c_int_to_u16(val: c_int) -> u16 {
54    if val >= 0 && val <= u16::MAX as c_int {
55        val as u16
56    } else {
57        panic!("Slot ID out of range for u16");
58    }
59}
60
61#[cfg(Py_3_15)]
62pub const fn PySlot_DATA(NAME: c_int, VALUE: *mut c_void) -> PySlot {
63    PySlot {
64        sl_id: safe_cast_c_int_to_u16(NAME),
65        sl_flags: PySlot_INTPTR,
66        anon1: _anon_union_32b { sl_reserved: 0 },
67        anon2: _anon_union_64b { sl_ptr: VALUE },
68    }
69}
70
71#[expect(clippy::incompatible_msrv, reason = "guarded by cfg(const_is_null)")]
72#[cfg(Py_3_15)]
73pub const unsafe fn PySlot_FUNC(NAME: c_int, VALUE: *mut c_void) -> PySlot {
74    #[cfg(const_is_null)]
75    assert!(!VALUE.is_null(), "value may not be null");
76    PySlot {
77        sl_id: safe_cast_c_int_to_u16(NAME),
78        sl_flags: 0,
79        anon1: _anon_union_32b { sl_reserved: 0 },
80        anon2: _anon_union_64b {
81            sl_func: Some(unsafe { core::mem::transmute::<*mut c_void, _Py_funcptr_t>(VALUE) }),
82        },
83    }
84}
85
86#[cfg(Py_3_15)]
87pub const fn PySlot_SIZE(NAME: c_int, VALUE: Py_ssize_t) -> PySlot {
88    PySlot {
89        sl_id: safe_cast_c_int_to_u16(NAME),
90        sl_flags: 0,
91        anon1: _anon_union_32b { sl_reserved: 0 },
92        anon2: _anon_union_64b { sl_size: VALUE },
93    }
94}
95
96#[cfg(Py_3_15)]
97pub const fn PySlot_INT64(NAME: c_int, VALUE: i64) -> PySlot {
98    PySlot {
99        sl_id: safe_cast_c_int_to_u16(NAME),
100        sl_flags: 0,
101        anon1: _anon_union_32b { sl_reserved: 0 },
102        anon2: _anon_union_64b { sl_int64: VALUE },
103    }
104}
105
106#[cfg(Py_3_15)]
107pub const fn PySlot_UINT64(NAME: c_int, VALUE: u64) -> PySlot {
108    PySlot {
109        sl_id: safe_cast_c_int_to_u16(NAME),
110        sl_flags: 0,
111        anon1: _anon_union_32b { sl_reserved: 0 },
112        anon2: _anon_union_64b { sl_uint64: VALUE },
113    }
114}
115
116#[cfg(Py_3_15)]
117pub const fn PySlot_STATIC_DATA(NAME: c_int, VALUE: *mut c_void) -> PySlot {
118    PySlot {
119        sl_id: safe_cast_c_int_to_u16(NAME),
120        sl_flags: PySlot_STATIC,
121        anon1: _anon_union_32b { sl_reserved: 0 },
122        anon2: _anon_union_64b { sl_ptr: VALUE },
123    }
124}
125
126#[cfg(Py_3_15)]
127pub const fn PySlot_PTR(NAME: c_int, VALUE: *mut c_void) -> PySlot {
128    PySlot {
129        sl_id: safe_cast_c_int_to_u16(NAME),
130        sl_flags: PySlot_INTPTR,
131        anon1: _anon_union_32b { sl_reserved: 0 },
132        anon2: _anon_union_64b { sl_ptr: VALUE },
133    }
134}
135
136#[cfg(Py_3_15)]
137pub const fn PySlot_PTR_STATIC(NAME: c_int, VALUE: *mut c_void) -> PySlot {
138    PySlot {
139        sl_id: safe_cast_c_int_to_u16(NAME),
140        sl_flags: PySlot_INTPTR | PySlot_STATIC,
141        anon1: _anon_union_32b { sl_reserved: 0 },
142        anon2: _anon_union_64b { sl_ptr: VALUE },
143    }
144}
145
146#[cfg(Py_3_15)]
147pub const fn PySlot_END() -> PySlot {
148    unsafe { core::mem::zeroed() }
149}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here