Skip to main content

rustpython_vm/types/
slot_defs.rs

1//! Slot definitions array
2//!
3//! This module provides a centralized array of all slot definitions,
4
5use super::{PyComparisonOp, PyTypeSlots, fn_addr};
6use crate::builtins::descriptor::SlotFunc;
7
8/// Slot operation type
9///
10/// Used to distinguish between different operations that share the same slot:
11/// - RichCompare: Lt, Le, Eq, Ne, Gt, Ge
12/// - Binary ops: Left (__add__) vs Right (__radd__)
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum SlotOp {
15    // RichCompare operations
16    Lt,
17    Le,
18    Eq,
19    Ne,
20    Gt,
21    Ge,
22    // Binary operation direction
23    Left,
24    Right,
25    // Setter vs Deleter
26    Delete,
27}
28
29impl SlotOp {
30    /// Convert to PyComparisonOp if this is a comparison operation
31    #[must_use]
32    pub fn as_compare_op(&self) -> Option<PyComparisonOp> {
33        match self {
34            Self::Lt => Some(PyComparisonOp::Lt),
35            Self::Le => Some(PyComparisonOp::Le),
36            Self::Eq => Some(PyComparisonOp::Eq),
37            Self::Ne => Some(PyComparisonOp::Ne),
38            Self::Gt => Some(PyComparisonOp::Gt),
39            Self::Ge => Some(PyComparisonOp::Ge),
40            _ => None,
41        }
42    }
43
44    /// Check if this is a right operation (__radd__, __rsub__, etc.)
45    #[must_use]
46    pub fn is_right(&self) -> bool {
47        matches!(self, Self::Right)
48    }
49}
50
51/// Slot definition entry
52#[derive(Clone, Copy)]
53pub struct SlotDef {
54    /// Method name ("__init__", "__add__", etc.)
55    pub name: &'static str,
56
57    /// Slot accessor (which slot field to access)
58    pub accessor: SlotAccessor,
59
60    /// Operation type (for shared slots like RichCompare, binary ops)
61    pub op: Option<SlotOp>,
62
63    /// Documentation string
64    pub doc: &'static str,
65}
66
67/// Slot accessor
68///
69/// Values match CPython's Py_* slot IDs from typeslots.h.
70/// Unused slots are included for value reservation.
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72#[repr(u8)]
73pub enum SlotAccessor {
74    // Buffer protocol (1-2)
75    BfGetBuffer = 1,
76    BfReleaseBuffer = 2,
77
78    // Mapping protocol (3-5)
79    MpAssSubscript = 3,
80    MpLength = 4,
81    MpSubscript = 5,
82
83    // Number protocol (6-38)
84    NbAbsolute = 6,
85    NbAdd = 7,
86    NbAnd = 8,
87    NbBool = 9,
88    NbDivmod = 10,
89    NbFloat = 11,
90    NbFloorDivide = 12,
91    NbIndex = 13,
92    NbInplaceAdd = 14,
93    NbInplaceAnd = 15,
94    NbInplaceFloorDivide = 16,
95    NbInplaceLshift = 17,
96    NbInplaceMultiply = 18,
97    NbInplaceOr = 19,
98    NbInplacePower = 20,
99    NbInplaceRemainder = 21,
100    NbInplaceRshift = 22,
101    NbInplaceSubtract = 23,
102    NbInplaceTrueDivide = 24,
103    NbInplaceXor = 25,
104    NbInt = 26,
105    NbInvert = 27,
106    NbLshift = 28,
107    NbMultiply = 29,
108    NbNegative = 30,
109    NbOr = 31,
110    NbPositive = 32,
111    NbPower = 33,
112    NbRemainder = 34,
113    NbRshift = 35,
114    NbSubtract = 36,
115    NbTrueDivide = 37,
116    NbXor = 38,
117
118    // Sequence protocol (39-46)
119    SqAssItem = 39,
120    SqConcat = 40,
121    SqContains = 41,
122    SqInplaceConcat = 42,
123    SqInplaceRepeat = 43,
124    SqItem = 44,
125    SqLength = 45,
126    SqRepeat = 46,
127
128    // Type slots (47-74)
129    TpAlloc = 47, // Reserved
130    TpBase = 48,  // Reserved
131    TpBases = 49, // Reserved
132    TpCall = 50,
133    TpClear = 51,   // Reserved
134    TpDealloc = 52, // Reserved
135    TpDel = 53,
136    TpDescrGet = 54,
137    TpDescrSet = 55,
138    TpDoc = 56,     // Reserved
139    TpGetattr = 57, // Reserved (use TpGetattro)
140    TpGetattro = 58,
141    TpHash = 59,
142    TpInit = 60,
143    TpIsGc = 61, // Reserved
144    TpIter = 62,
145    TpIternext = 63,
146    TpMethods = 64, // Reserved
147    TpNew = 65,
148    TpRepr = 66,
149    TpRichcompare = 67,
150    TpSetattr = 68, // Reserved (use TpSetattro)
151    TpSetattro = 69,
152    TpStr = 70,
153    TpTraverse = 71, // Reserved
154    TpMembers = 72,  // Reserved
155    TpGetset = 73,   // Reserved
156    TpFree = 74,     // Reserved
157
158    // Number protocol additions (75-76)
159    NbMatrixMultiply = 75,
160    NbInplaceMatrixMultiply = 76,
161
162    // Async protocol (77-81) - Reserved for future
163    AmAwait = 77,
164    AmAiter = 78,
165    AmAnext = 79,
166    TpFinalize = 80,
167    AmSend = 81,
168}
169
170impl SlotAccessor {
171    /// Check if this accessor is for a reserved/unused slot
172    #[must_use]
173    pub fn is_reserved(&self) -> bool {
174        matches!(
175            self,
176            Self::TpAlloc
177                | Self::TpBase
178                | Self::TpBases
179                | Self::TpClear
180                | Self::TpDealloc
181                | Self::TpDoc
182                | Self::TpGetattr
183                | Self::TpIsGc
184                | Self::TpMethods
185                | Self::TpSetattr
186                | Self::TpTraverse
187                | Self::TpMembers
188                | Self::TpGetset
189                | Self::TpFree
190                | Self::TpFinalize
191                | Self::AmAwait
192                | Self::AmAiter
193                | Self::AmAnext
194                | Self::AmSend
195        )
196    }
197
198    /// Check if this is a number binary operation slot
199    #[must_use]
200    pub fn is_number_binary(&self) -> bool {
201        matches!(
202            self,
203            Self::NbAdd
204                | Self::NbSubtract
205                | Self::NbMultiply
206                | Self::NbRemainder
207                | Self::NbDivmod
208                | Self::NbPower
209                | Self::NbLshift
210                | Self::NbRshift
211                | Self::NbAnd
212                | Self::NbXor
213                | Self::NbOr
214                | Self::NbFloorDivide
215                | Self::NbTrueDivide
216                | Self::NbMatrixMultiply
217        )
218    }
219
220    /// Check if this accessor refers to a shared slot
221    ///
222    /// Shared slots are used by multiple dunder methods:
223    /// - TpSetattro: __setattr__ and __delattr__
224    /// - TpRichcompare: __lt__, __le__, __eq__, __ne__, __gt__, __ge__
225    /// - TpDescrSet: __set__ and __delete__
226    /// - SqAssItem/MpAssSubscript: __setitem__ and __delitem__
227    /// - Number binaries: __add__ and __radd__, etc.
228    #[must_use]
229    pub fn is_shared_slot(&self) -> bool {
230        matches!(
231            self,
232            Self::TpSetattro
233                | Self::TpRichcompare
234                | Self::TpDescrSet
235                | Self::SqAssItem
236                | Self::MpAssSubscript
237        ) || self.is_number_binary()
238    }
239
240    /// Get underlying slot field name for debugging
241    #[must_use]
242    pub fn slot_name(&self) -> &'static str {
243        match self {
244            Self::BfGetBuffer => "bf_getbuffer",
245            Self::BfReleaseBuffer => "bf_releasebuffer",
246            Self::MpAssSubscript => "mp_ass_subscript",
247            Self::MpLength => "mp_length",
248            Self::MpSubscript => "mp_subscript",
249            Self::NbAbsolute => "nb_absolute",
250            Self::NbAdd => "nb_add",
251            Self::NbAnd => "nb_and",
252            Self::NbBool => "nb_bool",
253            Self::NbDivmod => "nb_divmod",
254            Self::NbFloat => "nb_float",
255            Self::NbFloorDivide => "nb_floor_divide",
256            Self::NbIndex => "nb_index",
257            Self::NbInplaceAdd => "nb_inplace_add",
258            Self::NbInplaceAnd => "nb_inplace_and",
259            Self::NbInplaceFloorDivide => "nb_inplace_floor_divide",
260            Self::NbInplaceLshift => "nb_inplace_lshift",
261            Self::NbInplaceMultiply => "nb_inplace_multiply",
262            Self::NbInplaceOr => "nb_inplace_or",
263            Self::NbInplacePower => "nb_inplace_power",
264            Self::NbInplaceRemainder => "nb_inplace_remainder",
265            Self::NbInplaceRshift => "nb_inplace_rshift",
266            Self::NbInplaceSubtract => "nb_inplace_subtract",
267            Self::NbInplaceTrueDivide => "nb_inplace_true_divide",
268            Self::NbInplaceXor => "nb_inplace_xor",
269            Self::NbInt => "nb_int",
270            Self::NbInvert => "nb_invert",
271            Self::NbLshift => "nb_lshift",
272            Self::NbMultiply => "nb_multiply",
273            Self::NbNegative => "nb_negative",
274            Self::NbOr => "nb_or",
275            Self::NbPositive => "nb_positive",
276            Self::NbPower => "nb_power",
277            Self::NbRemainder => "nb_remainder",
278            Self::NbRshift => "nb_rshift",
279            Self::NbSubtract => "nb_subtract",
280            Self::NbTrueDivide => "nb_true_divide",
281            Self::NbXor => "nb_xor",
282            Self::SqAssItem => "sq_ass_item",
283            Self::SqConcat => "sq_concat",
284            Self::SqContains => "sq_contains",
285            Self::SqInplaceConcat => "sq_inplace_concat",
286            Self::SqInplaceRepeat => "sq_inplace_repeat",
287            Self::SqItem => "sq_item",
288            Self::SqLength => "sq_length",
289            Self::SqRepeat => "sq_repeat",
290            Self::TpAlloc => "tp_alloc",
291            Self::TpBase => "tp_base",
292            Self::TpBases => "tp_bases",
293            Self::TpCall => "tp_call",
294            Self::TpClear => "tp_clear",
295            Self::TpDealloc => "tp_dealloc",
296            Self::TpDel => "tp_del",
297            Self::TpDescrGet => "tp_descr_get",
298            Self::TpDescrSet => "tp_descr_set",
299            Self::TpDoc => "tp_doc",
300            Self::TpGetattr => "tp_getattr",
301            Self::TpGetattro => "tp_getattro",
302            Self::TpHash => "tp_hash",
303            Self::TpInit => "tp_init",
304            Self::TpIsGc => "tp_is_gc",
305            Self::TpIter => "tp_iter",
306            Self::TpIternext => "tp_iternext",
307            Self::TpMethods => "tp_methods",
308            Self::TpNew => "tp_new",
309            Self::TpRepr => "tp_repr",
310            Self::TpRichcompare => "tp_richcompare",
311            Self::TpSetattr => "tp_setattr",
312            Self::TpSetattro => "tp_setattro",
313            Self::TpStr => "tp_str",
314            Self::TpTraverse => "tp_traverse",
315            Self::TpMembers => "tp_members",
316            Self::TpGetset => "tp_getset",
317            Self::TpFree => "tp_free",
318            Self::NbMatrixMultiply => "nb_matrix_multiply",
319            Self::NbInplaceMatrixMultiply => "nb_inplace_matrix_multiply",
320            Self::AmAwait => "am_await",
321            Self::AmAiter => "am_aiter",
322            Self::AmAnext => "am_anext",
323            Self::TpFinalize => "tp_finalize",
324            Self::AmSend => "am_send",
325        }
326    }
327
328    /// Extract the raw function pointer from a SlotFunc if it matches this accessor's type
329    #[must_use]
330    pub fn extract_from_slot_func(&self, slot_func: &SlotFunc) -> bool {
331        match self {
332            // Type slots
333            Self::TpHash => matches!(slot_func, SlotFunc::Hash(_)),
334            Self::TpRepr => matches!(slot_func, SlotFunc::Repr(_)),
335            Self::TpStr => matches!(slot_func, SlotFunc::Str(_)),
336            Self::TpCall => matches!(slot_func, SlotFunc::Call(_)),
337            Self::TpIter => matches!(slot_func, SlotFunc::Iter(_)),
338            Self::TpIternext => matches!(slot_func, SlotFunc::IterNext(_)),
339            Self::TpInit => matches!(slot_func, SlotFunc::Init(_)),
340            Self::TpDel => matches!(slot_func, SlotFunc::Del(_)),
341            Self::TpGetattro => matches!(slot_func, SlotFunc::GetAttro(_)),
342            Self::TpSetattro => {
343                matches!(slot_func, SlotFunc::SetAttro(_) | SlotFunc::DelAttro(_))
344            }
345            Self::TpDescrGet => matches!(slot_func, SlotFunc::DescrGet(_)),
346            Self::TpDescrSet => {
347                matches!(slot_func, SlotFunc::DescrSet(_) | SlotFunc::DescrDel(_))
348            }
349            Self::TpRichcompare => matches!(slot_func, SlotFunc::RichCompare(_, _)),
350
351            // Number - Power (ternary)
352            Self::NbPower | Self::NbInplacePower => {
353                matches!(slot_func, SlotFunc::NumTernary(_))
354            }
355            // Number - Boolean
356            Self::NbBool => matches!(slot_func, SlotFunc::NumBoolean(_)),
357            // Number - Unary
358            Self::NbNegative
359            | Self::NbPositive
360            | Self::NbAbsolute
361            | Self::NbInvert
362            | Self::NbInt
363            | Self::NbFloat
364            | Self::NbIndex => matches!(slot_func, SlotFunc::NumUnary(_)),
365            // Number - Binary
366            Self::NbAdd
367            | Self::NbSubtract
368            | Self::NbMultiply
369            | Self::NbRemainder
370            | Self::NbDivmod
371            | Self::NbLshift
372            | Self::NbRshift
373            | Self::NbAnd
374            | Self::NbXor
375            | Self::NbOr
376            | Self::NbFloorDivide
377            | Self::NbTrueDivide
378            | Self::NbMatrixMultiply
379            | Self::NbInplaceAdd
380            | Self::NbInplaceSubtract
381            | Self::NbInplaceMultiply
382            | Self::NbInplaceRemainder
383            | Self::NbInplaceLshift
384            | Self::NbInplaceRshift
385            | Self::NbInplaceAnd
386            | Self::NbInplaceXor
387            | Self::NbInplaceOr
388            | Self::NbInplaceFloorDivide
389            | Self::NbInplaceTrueDivide
390            | Self::NbInplaceMatrixMultiply => matches!(slot_func, SlotFunc::NumBinary(_)),
391
392            // Sequence
393            Self::SqLength => matches!(slot_func, SlotFunc::SeqLength(_)),
394            Self::SqConcat | Self::SqInplaceConcat => matches!(slot_func, SlotFunc::SeqConcat(_)),
395            Self::SqRepeat | Self::SqInplaceRepeat => matches!(slot_func, SlotFunc::SeqRepeat(_)),
396            Self::SqItem => matches!(slot_func, SlotFunc::SeqItem(_)),
397            Self::SqAssItem => {
398                matches!(slot_func, SlotFunc::SeqSetItem(_) | SlotFunc::SeqDelItem(_))
399            }
400            Self::SqContains => matches!(slot_func, SlotFunc::SeqContains(_)),
401
402            // Mapping
403            Self::MpLength => matches!(slot_func, SlotFunc::MapLength(_)),
404            Self::MpSubscript => matches!(slot_func, SlotFunc::MapSubscript(_)),
405            Self::MpAssSubscript => {
406                matches!(
407                    slot_func,
408                    SlotFunc::MapSetSubscript(_) | SlotFunc::MapDelSubscript(_)
409                )
410            }
411
412            // Buffer protocol
413            Self::BfGetBuffer => matches!(slot_func, SlotFunc::GetBuffer(_)),
414            Self::BfReleaseBuffer => matches!(slot_func, SlotFunc::ReleaseBuffer),
415
416            // New and reserved slots
417            Self::TpNew => false,
418            _ => false, // Reserved slots
419        }
420    }
421
422    /// Inherit slot value from MRO
423    pub fn inherit_from_mro(&self, typ: &crate::builtins::PyType) {
424        // mro[0] is self, so skip it
425        let mro_guard = typ.mro.read();
426        let mro = &mro_guard[1..];
427
428        macro_rules! inherit_main {
429            ($slot:ident) => {{
430                let inherited = mro.iter().find_map(|cls| cls.payload().slots.$slot.load());
431                typ.slots.$slot.store(inherited);
432            }};
433        }
434
435        macro_rules! inherit_number {
436            ($slot:ident) => {{
437                let inherited = mro
438                    .iter()
439                    .find_map(|cls| cls.payload().slots.as_number.$slot.load());
440                typ.slots.as_number.$slot.store(inherited);
441            }};
442        }
443
444        macro_rules! inherit_sequence {
445            ($slot:ident) => {{
446                let inherited = mro
447                    .iter()
448                    .find_map(|cls| cls.payload().slots.as_sequence.$slot.load());
449                typ.slots.as_sequence.$slot.store(inherited);
450            }};
451        }
452
453        macro_rules! inherit_mapping {
454            ($slot:ident) => {{
455                let inherited = mro
456                    .iter()
457                    .find_map(|cls| cls.payload().slots.as_mapping.$slot.load());
458                typ.slots.as_mapping.$slot.store(inherited);
459            }};
460        }
461
462        match self {
463            // Type slots
464            Self::TpHash => inherit_main!(hash),
465            Self::TpRepr => inherit_main!(repr),
466            Self::TpStr => inherit_main!(str),
467            Self::TpCall => {
468                inherit_main!(call);
469                // CPython does not inherit tp_vectorcall to heap types at all; it only
470                // inherits tp_vectorcall_offset (the per-instance callable fast path).
471                // RustPython approximates this by inheriting vectorcall only from types
472                // with a call slot (instance-call vectorcall), not from types that use
473                // vectorcall as a constructor fast path (call=None).
474                // See vectorcall_type() in type.rs for the dual-use design rationale.
475                let inherited_vc = mro.iter().find_map(|cls| {
476                    if cls.payload().slots.call.load().is_some() {
477                        cls.payload().slots.vectorcall.load()
478                    } else {
479                        None
480                    }
481                });
482                typ.slots.vectorcall.store(inherited_vc);
483            }
484            Self::TpIter => inherit_main!(iter),
485            Self::TpIternext => inherit_main!(iternext),
486            Self::TpInit => inherit_main!(init),
487            Self::TpNew => inherit_main!(new),
488            Self::TpDel => inherit_main!(del),
489            Self::TpGetattro => inherit_main!(getattro),
490            Self::TpSetattro => inherit_main!(setattro),
491            Self::TpDescrGet => inherit_main!(descr_get),
492            Self::TpDescrSet => inherit_main!(descr_set),
493            Self::TpRichcompare => inherit_main!(richcompare),
494
495            // Number slots
496            Self::NbAdd => inherit_number!(add),
497            Self::NbSubtract => inherit_number!(subtract),
498            Self::NbMultiply => inherit_number!(multiply),
499            Self::NbRemainder => inherit_number!(remainder),
500            Self::NbDivmod => inherit_number!(divmod),
501            Self::NbPower => inherit_number!(power),
502            Self::NbLshift => inherit_number!(lshift),
503            Self::NbRshift => inherit_number!(rshift),
504            Self::NbAnd => inherit_number!(and),
505            Self::NbXor => inherit_number!(xor),
506            Self::NbOr => inherit_number!(or),
507            Self::NbFloorDivide => inherit_number!(floor_divide),
508            Self::NbTrueDivide => inherit_number!(true_divide),
509            Self::NbMatrixMultiply => inherit_number!(matrix_multiply),
510            Self::NbInplaceAdd => inherit_number!(inplace_add),
511            Self::NbInplaceSubtract => inherit_number!(inplace_subtract),
512            Self::NbInplaceMultiply => inherit_number!(inplace_multiply),
513            Self::NbInplaceRemainder => inherit_number!(inplace_remainder),
514            Self::NbInplacePower => inherit_number!(inplace_power),
515            Self::NbInplaceLshift => inherit_number!(inplace_lshift),
516            Self::NbInplaceRshift => inherit_number!(inplace_rshift),
517            Self::NbInplaceAnd => inherit_number!(inplace_and),
518            Self::NbInplaceXor => inherit_number!(inplace_xor),
519            Self::NbInplaceOr => inherit_number!(inplace_or),
520            Self::NbInplaceFloorDivide => inherit_number!(inplace_floor_divide),
521            Self::NbInplaceTrueDivide => inherit_number!(inplace_true_divide),
522            Self::NbInplaceMatrixMultiply => inherit_number!(inplace_matrix_multiply),
523            // Number unary
524            Self::NbNegative => inherit_number!(negative),
525            Self::NbPositive => inherit_number!(positive),
526            Self::NbAbsolute => inherit_number!(absolute),
527            Self::NbInvert => inherit_number!(invert),
528            Self::NbBool => inherit_number!(boolean),
529            Self::NbInt => inherit_number!(int),
530            Self::NbFloat => inherit_number!(float),
531            Self::NbIndex => inherit_number!(index),
532
533            // Sequence slots
534            Self::SqLength => inherit_sequence!(length),
535            Self::SqConcat => inherit_sequence!(concat),
536            Self::SqRepeat => inherit_sequence!(repeat),
537            Self::SqItem => inherit_sequence!(item),
538            Self::SqAssItem => inherit_sequence!(ass_item),
539            Self::SqContains => inherit_sequence!(contains),
540            Self::SqInplaceConcat => inherit_sequence!(inplace_concat),
541            Self::SqInplaceRepeat => inherit_sequence!(inplace_repeat),
542
543            // Mapping slots
544            Self::MpLength => inherit_mapping!(length),
545            Self::MpSubscript => inherit_mapping!(subscript),
546            Self::MpAssSubscript => inherit_mapping!(ass_subscript),
547
548            // Buffer protocol
549            Self::BfGetBuffer => {
550                let inherited = mro
551                    .iter()
552                    .find_map(|cls| cls.payload().slots.as_buffer.load());
553                typ.slots.as_buffer.store(inherited);
554            }
555            Self::BfReleaseBuffer => {
556                let has_release = mro
557                    .iter()
558                    .any(|cls| cls.payload().slots.has_release_buffer.load());
559                typ.slots.has_release_buffer.store(has_release);
560                let py_release = mro
561                    .iter()
562                    .any(|cls| cls.payload().slots.python_release_buffer.load());
563                typ.slots.python_release_buffer.store(py_release);
564            }
565
566            // Reserved slots - no-op
567            _ => {}
568        }
569    }
570
571    /// Copy slot from base type if self's slot is None
572    pub fn copyslot_if_none(&self, typ: &crate::builtins::PyType, base: &crate::builtins::PyType) {
573        macro_rules! copy_main {
574            ($slot:ident) => {{
575                if typ.slots.$slot.load().is_none() {
576                    if let Some(base_val) = base.slots.$slot.load() {
577                        typ.slots.$slot.store(Some(base_val));
578                    }
579                }
580            }};
581        }
582
583        macro_rules! copy_number {
584            ($slot:ident) => {{
585                if typ.slots.as_number.$slot.load().is_none() {
586                    if let Some(base_val) = base.slots.as_number.$slot.load() {
587                        typ.slots.as_number.$slot.store(Some(base_val));
588                    }
589                }
590            }};
591        }
592
593        macro_rules! copy_sequence {
594            ($slot:ident) => {{
595                if typ.slots.as_sequence.$slot.load().is_none() {
596                    if let Some(base_val) = base.slots.as_sequence.$slot.load() {
597                        typ.slots.as_sequence.$slot.store(Some(base_val));
598                    }
599                }
600            }};
601        }
602
603        macro_rules! copy_mapping {
604            ($slot:ident) => {{
605                if typ.slots.as_mapping.$slot.load().is_none() {
606                    if let Some(base_val) = base.slots.as_mapping.$slot.load() {
607                        typ.slots.as_mapping.$slot.store(Some(base_val));
608                    }
609                }
610            }};
611        }
612
613        match self {
614            // Type slots
615            Self::TpHash => copy_main!(hash),
616            Self::TpRepr => copy_main!(repr),
617            Self::TpStr => copy_main!(str),
618            Self::TpCall => {
619                copy_main!(call);
620                // See inherit_from_mro TpCall for rationale.
621                if typ.slots.vectorcall.load().is_none()
622                    && base.slots.call.load().is_some()
623                    && let Some(base_val) = base.slots.vectorcall.load()
624                {
625                    typ.slots.vectorcall.store(Some(base_val));
626                }
627            }
628            Self::TpIter => copy_main!(iter),
629            Self::TpIternext => copy_main!(iternext),
630            Self::TpInit => {
631                // SLOTDEFINED check for multiple inheritance support
632                if typ.slots.init.load().is_none()
633                    && let Some(base_val) = base.slots.init.load()
634                {
635                    let slot_defined = base.base.deref().is_none_or(|bb| {
636                        bb.payload().slots.init.load().map(|v| fn_addr(v))
637                            != Some(fn_addr(base_val))
638                    });
639                    if slot_defined {
640                        typ.slots.init.store(Some(base_val));
641                    }
642                }
643            }
644            Self::TpNew => {} // handled by set_new()
645            Self::TpDel => copy_main!(del),
646            Self::TpGetattro => copy_main!(getattro),
647            Self::TpSetattro => copy_main!(setattro),
648            Self::TpDescrGet => copy_main!(descr_get),
649            Self::TpDescrSet => copy_main!(descr_set),
650            Self::TpRichcompare => copy_main!(richcompare),
651
652            // Number slots
653            Self::NbAdd => copy_number!(add),
654            Self::NbSubtract => copy_number!(subtract),
655            Self::NbMultiply => copy_number!(multiply),
656            Self::NbRemainder => copy_number!(remainder),
657            Self::NbDivmod => copy_number!(divmod),
658            Self::NbPower => copy_number!(power),
659            Self::NbLshift => copy_number!(lshift),
660            Self::NbRshift => copy_number!(rshift),
661            Self::NbAnd => copy_number!(and),
662            Self::NbXor => copy_number!(xor),
663            Self::NbOr => copy_number!(or),
664            Self::NbFloorDivide => copy_number!(floor_divide),
665            Self::NbTrueDivide => copy_number!(true_divide),
666            Self::NbMatrixMultiply => copy_number!(matrix_multiply),
667            Self::NbInplaceAdd => copy_number!(inplace_add),
668            Self::NbInplaceSubtract => copy_number!(inplace_subtract),
669            Self::NbInplaceMultiply => copy_number!(inplace_multiply),
670            Self::NbInplaceRemainder => copy_number!(inplace_remainder),
671            Self::NbInplacePower => copy_number!(inplace_power),
672            Self::NbInplaceLshift => copy_number!(inplace_lshift),
673            Self::NbInplaceRshift => copy_number!(inplace_rshift),
674            Self::NbInplaceAnd => copy_number!(inplace_and),
675            Self::NbInplaceXor => copy_number!(inplace_xor),
676            Self::NbInplaceOr => copy_number!(inplace_or),
677            Self::NbInplaceFloorDivide => copy_number!(inplace_floor_divide),
678            Self::NbInplaceTrueDivide => copy_number!(inplace_true_divide),
679            Self::NbInplaceMatrixMultiply => copy_number!(inplace_matrix_multiply),
680            // Number unary
681            Self::NbNegative => copy_number!(negative),
682            Self::NbPositive => copy_number!(positive),
683            Self::NbAbsolute => copy_number!(absolute),
684            Self::NbInvert => copy_number!(invert),
685            Self::NbBool => copy_number!(boolean),
686            Self::NbInt => copy_number!(int),
687            Self::NbFloat => copy_number!(float),
688            Self::NbIndex => copy_number!(index),
689
690            // Sequence slots
691            Self::SqLength => copy_sequence!(length),
692            Self::SqConcat => copy_sequence!(concat),
693            Self::SqRepeat => copy_sequence!(repeat),
694            Self::SqItem => copy_sequence!(item),
695            Self::SqAssItem => copy_sequence!(ass_item),
696            Self::SqContains => copy_sequence!(contains),
697            Self::SqInplaceConcat => copy_sequence!(inplace_concat),
698            Self::SqInplaceRepeat => copy_sequence!(inplace_repeat),
699
700            // Mapping slots
701            Self::MpLength => copy_mapping!(length),
702            Self::MpSubscript => copy_mapping!(subscript),
703            Self::MpAssSubscript => copy_mapping!(ass_subscript),
704
705            // Buffer protocol
706            Self::BfGetBuffer => {
707                if typ.slots.as_buffer.load().is_none()
708                    && let Some(base_val) = base.slots.as_buffer.load()
709                {
710                    typ.slots.as_buffer.store(Some(base_val));
711                }
712            }
713            Self::BfReleaseBuffer => {
714                if !typ.slots.has_release_buffer.load() && base.slots.has_release_buffer.load() {
715                    typ.slots.has_release_buffer.store(true);
716                }
717                if !typ.slots.python_release_buffer.load()
718                    && base.slots.python_release_buffer.load()
719                {
720                    typ.slots.python_release_buffer.store(true);
721                }
722            }
723
724            // Reserved slots - no-op
725            _ => {}
726        }
727    }
728
729    /// Get the SlotFunc from type slots for this accessor
730    pub fn get_slot_func(&self, slots: &PyTypeSlots) -> Option<SlotFunc> {
731        match self {
732            // Type slots
733            Self::TpHash => slots.hash.load().map(SlotFunc::Hash),
734            Self::TpRepr => slots.repr.load().map(SlotFunc::Repr),
735            Self::TpStr => slots.str.load().map(SlotFunc::Str),
736            Self::TpCall => slots.call.load().map(SlotFunc::Call),
737            Self::TpIter => slots.iter.load().map(SlotFunc::Iter),
738            Self::TpIternext => slots.iternext.load().map(SlotFunc::IterNext),
739            Self::TpInit => slots.init.load().map(SlotFunc::Init),
740            Self::TpNew => None, // __new__ handled separately
741            Self::TpDel => slots.del.load().map(SlotFunc::Del),
742            Self::TpGetattro => slots.getattro.load().map(SlotFunc::GetAttro),
743            Self::TpSetattro => slots.setattro.load().map(SlotFunc::SetAttro),
744            Self::TpDescrGet => slots.descr_get.load().map(SlotFunc::DescrGet),
745            Self::TpDescrSet => slots.descr_set.load().map(SlotFunc::DescrSet),
746            Self::TpRichcompare => slots
747                .richcompare
748                .load()
749                .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Eq)),
750
751            // Number binary slots
752            Self::NbAdd => slots.as_number.add.load().map(SlotFunc::NumBinary),
753            Self::NbSubtract => slots.as_number.subtract.load().map(SlotFunc::NumBinary),
754            Self::NbMultiply => slots.as_number.multiply.load().map(SlotFunc::NumBinary),
755            Self::NbRemainder => slots.as_number.remainder.load().map(SlotFunc::NumBinary),
756            Self::NbDivmod => slots.as_number.divmod.load().map(SlotFunc::NumBinary),
757            Self::NbPower => slots.as_number.power.load().map(SlotFunc::NumTernary),
758            Self::NbLshift => slots.as_number.lshift.load().map(SlotFunc::NumBinary),
759            Self::NbRshift => slots.as_number.rshift.load().map(SlotFunc::NumBinary),
760            Self::NbAnd => slots.as_number.and.load().map(SlotFunc::NumBinary),
761            Self::NbXor => slots.as_number.xor.load().map(SlotFunc::NumBinary),
762            Self::NbOr => slots.as_number.or.load().map(SlotFunc::NumBinary),
763            Self::NbFloorDivide => slots.as_number.floor_divide.load().map(SlotFunc::NumBinary),
764            Self::NbTrueDivide => slots.as_number.true_divide.load().map(SlotFunc::NumBinary),
765            Self::NbMatrixMultiply => slots
766                .as_number
767                .matrix_multiply
768                .load()
769                .map(SlotFunc::NumBinary),
770
771            // Number inplace slots
772            Self::NbInplaceAdd => slots.as_number.inplace_add.load().map(SlotFunc::NumBinary),
773            Self::NbInplaceSubtract => slots
774                .as_number
775                .inplace_subtract
776                .load()
777                .map(SlotFunc::NumBinary),
778            Self::NbInplaceMultiply => slots
779                .as_number
780                .inplace_multiply
781                .load()
782                .map(SlotFunc::NumBinary),
783            Self::NbInplaceRemainder => slots
784                .as_number
785                .inplace_remainder
786                .load()
787                .map(SlotFunc::NumBinary),
788            Self::NbInplacePower => slots
789                .as_number
790                .inplace_power
791                .load()
792                .map(SlotFunc::NumTernary),
793            Self::NbInplaceLshift => slots
794                .as_number
795                .inplace_lshift
796                .load()
797                .map(SlotFunc::NumBinary),
798            Self::NbInplaceRshift => slots
799                .as_number
800                .inplace_rshift
801                .load()
802                .map(SlotFunc::NumBinary),
803            Self::NbInplaceAnd => slots.as_number.inplace_and.load().map(SlotFunc::NumBinary),
804            Self::NbInplaceXor => slots.as_number.inplace_xor.load().map(SlotFunc::NumBinary),
805            Self::NbInplaceOr => slots.as_number.inplace_or.load().map(SlotFunc::NumBinary),
806            Self::NbInplaceFloorDivide => slots
807                .as_number
808                .inplace_floor_divide
809                .load()
810                .map(SlotFunc::NumBinary),
811            Self::NbInplaceTrueDivide => slots
812                .as_number
813                .inplace_true_divide
814                .load()
815                .map(SlotFunc::NumBinary),
816            Self::NbInplaceMatrixMultiply => slots
817                .as_number
818                .inplace_matrix_multiply
819                .load()
820                .map(SlotFunc::NumBinary),
821
822            // Number unary slots
823            Self::NbNegative => slots.as_number.negative.load().map(SlotFunc::NumUnary),
824            Self::NbPositive => slots.as_number.positive.load().map(SlotFunc::NumUnary),
825            Self::NbAbsolute => slots.as_number.absolute.load().map(SlotFunc::NumUnary),
826            Self::NbInvert => slots.as_number.invert.load().map(SlotFunc::NumUnary),
827            Self::NbBool => slots.as_number.boolean.load().map(SlotFunc::NumBoolean),
828            Self::NbInt => slots.as_number.int.load().map(SlotFunc::NumUnary),
829            Self::NbFloat => slots.as_number.float.load().map(SlotFunc::NumUnary),
830            Self::NbIndex => slots.as_number.index.load().map(SlotFunc::NumUnary),
831
832            // Sequence slots
833            Self::SqLength => slots.as_sequence.length.load().map(SlotFunc::SeqLength),
834            Self::SqConcat => slots.as_sequence.concat.load().map(SlotFunc::SeqConcat),
835            Self::SqRepeat => slots.as_sequence.repeat.load().map(SlotFunc::SeqRepeat),
836            Self::SqItem => slots.as_sequence.item.load().map(SlotFunc::SeqItem),
837            Self::SqAssItem => slots.as_sequence.ass_item.load().map(SlotFunc::SeqSetItem),
838            Self::SqContains => slots.as_sequence.contains.load().map(SlotFunc::SeqContains),
839            Self::SqInplaceConcat => slots
840                .as_sequence
841                .inplace_concat
842                .load()
843                .map(SlotFunc::SeqConcat),
844            Self::SqInplaceRepeat => slots
845                .as_sequence
846                .inplace_repeat
847                .load()
848                .map(SlotFunc::SeqRepeat),
849
850            // Mapping slots
851            Self::MpLength => slots.as_mapping.length.load().map(SlotFunc::MapLength),
852            Self::MpSubscript => slots
853                .as_mapping
854                .subscript
855                .load()
856                .map(SlotFunc::MapSubscript),
857            Self::MpAssSubscript => slots
858                .as_mapping
859                .ass_subscript
860                .load()
861                .map(SlotFunc::MapSetSubscript),
862
863            // Buffer protocol
864            Self::BfGetBuffer => slots.as_buffer.load().map(SlotFunc::GetBuffer),
865            Self::BfReleaseBuffer => {
866                if slots.has_release_buffer.load() || slots.python_release_buffer.load() {
867                    Some(SlotFunc::ReleaseBuffer)
868                } else {
869                    None
870                }
871            }
872
873            // Reserved slots
874            _ => None,
875        }
876    }
877
878    /// Get slot function considering SlotOp for right-hand and delete operations
879    pub fn get_slot_func_with_op(
880        &self,
881        slots: &PyTypeSlots,
882        op: Option<SlotOp>,
883    ) -> Option<SlotFunc> {
884        // For Delete operations, return the delete variant
885        if op == Some(SlotOp::Delete) {
886            match self {
887                Self::TpSetattro => return slots.setattro.load().map(SlotFunc::DelAttro),
888                Self::TpDescrSet => return slots.descr_set.load().map(SlotFunc::DescrDel),
889                Self::SqAssItem => {
890                    return slots.as_sequence.ass_item.load().map(SlotFunc::SeqDelItem);
891                }
892                Self::MpAssSubscript => {
893                    return slots
894                        .as_mapping
895                        .ass_subscript
896                        .load()
897                        .map(SlotFunc::MapDelSubscript);
898                }
899                _ => {}
900            }
901        }
902        // For Right operations on binary number slots, use right_* fields with swapped args
903        if op == Some(SlotOp::Right) {
904            match self {
905                Self::NbAdd => {
906                    return slots
907                        .as_number
908                        .right_add
909                        .load()
910                        .map(SlotFunc::NumBinaryRight);
911                }
912                Self::NbSubtract => {
913                    return slots
914                        .as_number
915                        .right_subtract
916                        .load()
917                        .map(SlotFunc::NumBinaryRight);
918                }
919                Self::NbMultiply => {
920                    return slots
921                        .as_number
922                        .right_multiply
923                        .load()
924                        .map(SlotFunc::NumBinaryRight);
925                }
926                Self::NbRemainder => {
927                    return slots
928                        .as_number
929                        .right_remainder
930                        .load()
931                        .map(SlotFunc::NumBinaryRight);
932                }
933                Self::NbDivmod => {
934                    return slots
935                        .as_number
936                        .right_divmod
937                        .load()
938                        .map(SlotFunc::NumBinaryRight);
939                }
940                Self::NbPower => {
941                    return slots
942                        .as_number
943                        .right_power
944                        .load()
945                        .map(SlotFunc::NumTernaryRight);
946                }
947                Self::NbLshift => {
948                    return slots
949                        .as_number
950                        .right_lshift
951                        .load()
952                        .map(SlotFunc::NumBinaryRight);
953                }
954                Self::NbRshift => {
955                    return slots
956                        .as_number
957                        .right_rshift
958                        .load()
959                        .map(SlotFunc::NumBinaryRight);
960                }
961                Self::NbAnd => {
962                    return slots
963                        .as_number
964                        .right_and
965                        .load()
966                        .map(SlotFunc::NumBinaryRight);
967                }
968                Self::NbXor => {
969                    return slots
970                        .as_number
971                        .right_xor
972                        .load()
973                        .map(SlotFunc::NumBinaryRight);
974                }
975                Self::NbOr => {
976                    return slots
977                        .as_number
978                        .right_or
979                        .load()
980                        .map(SlotFunc::NumBinaryRight);
981                }
982                Self::NbFloorDivide => {
983                    return slots
984                        .as_number
985                        .right_floor_divide
986                        .load()
987                        .map(SlotFunc::NumBinaryRight);
988                }
989                Self::NbTrueDivide => {
990                    return slots
991                        .as_number
992                        .right_true_divide
993                        .load()
994                        .map(SlotFunc::NumBinaryRight);
995                }
996                Self::NbMatrixMultiply => {
997                    return slots
998                        .as_number
999                        .right_matrix_multiply
1000                        .load()
1001                        .map(SlotFunc::NumBinaryRight);
1002                }
1003                _ => {}
1004            }
1005        }
1006        // For comparison operations, use the appropriate PyComparisonOp
1007        if let Self::TpRichcompare = self
1008            && let Some(cmp_op) = op.and_then(|o| o.as_compare_op())
1009        {
1010            return slots
1011                .richcompare
1012                .load()
1013                .map(|f| SlotFunc::RichCompare(f, cmp_op));
1014        }
1015        // Fall back to existing get_slot_func for left/other operations
1016        self.get_slot_func(slots)
1017    }
1018}
1019
1020/// Find all slot definitions with a given name
1021pub fn find_slot_defs_by_name(name: &str) -> impl Iterator<Item = &'static SlotDef> {
1022    SLOT_DEFS.iter().filter(move |def| def.name == name)
1023}
1024
1025/// All slot definitions
1026pub const SLOT_DEFS: &[SlotDef] = &[
1027    // Buffer protocol (bf_*)
1028    SlotDef {
1029        name: "__buffer__",
1030        accessor: SlotAccessor::BfGetBuffer,
1031        op: None,
1032        doc: "__buffer__($self, flags, /)\n--\n\nReturn a buffer object that exposes the underlying memory of the object.",
1033    },
1034    SlotDef {
1035        name: "__release_buffer__",
1036        accessor: SlotAccessor::BfReleaseBuffer,
1037        op: None,
1038        doc: "__release_buffer__($self, buffer, /)\n--\n\nRelease the buffer object that exposes the underlying memory of the object.",
1039    },
1040    // Type slots (tp_*)
1041    SlotDef {
1042        name: "__init__",
1043        accessor: SlotAccessor::TpInit,
1044        op: None,
1045        doc: "__init__($self, /, *args, **kwargs)\n--\n\nInitialize self.  See help(type(self)) for accurate signature.",
1046    },
1047    SlotDef {
1048        name: "__new__",
1049        accessor: SlotAccessor::TpNew,
1050        op: None,
1051        doc: "__new__($type, /, *args, **kwargs)\n--\n\nCreate and return new object.  See help(type) for accurate signature.",
1052    },
1053    SlotDef {
1054        name: "__del__",
1055        accessor: SlotAccessor::TpDel,
1056        op: None,
1057        doc: "__del__($self, /)\n--\n\nCalled when the instance is about to be destroyed.",
1058    },
1059    SlotDef {
1060        name: "__repr__",
1061        accessor: SlotAccessor::TpRepr,
1062        op: None,
1063        doc: "__repr__($self, /)\n--\n\nReturn repr(self).",
1064    },
1065    SlotDef {
1066        name: "__str__",
1067        accessor: SlotAccessor::TpStr,
1068        op: None,
1069        doc: "__str__($self, /)\n--\n\nReturn str(self).",
1070    },
1071    SlotDef {
1072        name: "__hash__",
1073        accessor: SlotAccessor::TpHash,
1074        op: None,
1075        doc: "__hash__($self, /)\n--\n\nReturn hash(self).",
1076    },
1077    SlotDef {
1078        name: "__call__",
1079        accessor: SlotAccessor::TpCall,
1080        op: None,
1081        doc: "__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.",
1082    },
1083    SlotDef {
1084        name: "__iter__",
1085        accessor: SlotAccessor::TpIter,
1086        op: None,
1087        doc: "__iter__($self, /)\n--\n\nImplement iter(self).",
1088    },
1089    SlotDef {
1090        name: "__next__",
1091        accessor: SlotAccessor::TpIternext,
1092        op: None,
1093        doc: "__next__($self, /)\n--\n\nImplement next(self).",
1094    },
1095    // Attribute access
1096    SlotDef {
1097        name: "__getattribute__",
1098        accessor: SlotAccessor::TpGetattro,
1099        op: None,
1100        doc: "__getattribute__($self, name, /)\n--\n\nReturn getattr(self, name).",
1101    },
1102    SlotDef {
1103        name: "__getattr__",
1104        accessor: SlotAccessor::TpGetattro,
1105        op: None,
1106        doc: "__getattr__($self, name, /)\n--\n\nImplement getattr(self, name).",
1107    },
1108    SlotDef {
1109        name: "__setattr__",
1110        accessor: SlotAccessor::TpSetattro,
1111        op: None,
1112        doc: "__setattr__($self, name, value, /)\n--\n\nImplement setattr(self, name, value).",
1113    },
1114    SlotDef {
1115        name: "__delattr__",
1116        accessor: SlotAccessor::TpSetattro,
1117        op: Some(SlotOp::Delete),
1118        doc: "__delattr__($self, name, /)\n--\n\nImplement delattr(self, name).",
1119    },
1120    // Rich comparison - all map to TpRichcompare with different op
1121    SlotDef {
1122        name: "__eq__",
1123        accessor: SlotAccessor::TpRichcompare,
1124        op: Some(SlotOp::Eq),
1125        doc: "__eq__($self, value, /)\n--\n\nReturn self==value.",
1126    },
1127    SlotDef {
1128        name: "__ne__",
1129        accessor: SlotAccessor::TpRichcompare,
1130        op: Some(SlotOp::Ne),
1131        doc: "__ne__($self, value, /)\n--\n\nReturn self!=value.",
1132    },
1133    SlotDef {
1134        name: "__lt__",
1135        accessor: SlotAccessor::TpRichcompare,
1136        op: Some(SlotOp::Lt),
1137        doc: "__lt__($self, value, /)\n--\n\nReturn self<value.",
1138    },
1139    SlotDef {
1140        name: "__le__",
1141        accessor: SlotAccessor::TpRichcompare,
1142        op: Some(SlotOp::Le),
1143        doc: "__le__($self, value, /)\n--\n\nReturn self<=value.",
1144    },
1145    SlotDef {
1146        name: "__gt__",
1147        accessor: SlotAccessor::TpRichcompare,
1148        op: Some(SlotOp::Gt),
1149        doc: "__gt__($self, value, /)\n--\n\nReturn self>value.",
1150    },
1151    SlotDef {
1152        name: "__ge__",
1153        accessor: SlotAccessor::TpRichcompare,
1154        op: Some(SlotOp::Ge),
1155        doc: "__ge__($self, value, /)\n--\n\nReturn self>=value.",
1156    },
1157    // Descriptor protocol
1158    SlotDef {
1159        name: "__get__",
1160        accessor: SlotAccessor::TpDescrGet,
1161        op: None,
1162        doc: "__get__($self, instance, owner=None, /)\n--\n\nReturn an attribute of instance, which is of type owner.",
1163    },
1164    SlotDef {
1165        name: "__set__",
1166        accessor: SlotAccessor::TpDescrSet,
1167        op: None,
1168        doc: "__set__($self, instance, value, /)\n--\n\nSet an attribute of instance to value.",
1169    },
1170    SlotDef {
1171        name: "__delete__",
1172        accessor: SlotAccessor::TpDescrSet,
1173        op: Some(SlotOp::Delete),
1174        doc: "__delete__($self, instance, /)\n--\n\nDelete an attribute of instance.",
1175    },
1176    // Mapping protocol (mp_*) - must come before Sequence protocol
1177    // so that mp_subscript wins over sq_item for __getitem__
1178    // (see CPython typeobject.c:10995-11006)
1179    SlotDef {
1180        name: "__len__",
1181        accessor: SlotAccessor::MpLength,
1182        op: None,
1183        doc: "__len__($self, /)\n--\n\nReturn len(self).",
1184    },
1185    SlotDef {
1186        name: "__getitem__",
1187        accessor: SlotAccessor::MpSubscript,
1188        op: None,
1189        doc: "__getitem__($self, key, /)\n--\n\nReturn self[key].",
1190    },
1191    SlotDef {
1192        name: "__setitem__",
1193        accessor: SlotAccessor::MpAssSubscript,
1194        op: None,
1195        doc: "__setitem__($self, key, value, /)\n--\n\nSet self[key] to value.",
1196    },
1197    SlotDef {
1198        name: "__delitem__",
1199        accessor: SlotAccessor::MpAssSubscript,
1200        op: Some(SlotOp::Delete),
1201        doc: "__delitem__($self, key, /)\n--\n\nDelete self[key].",
1202    },
1203    // Sequence protocol (sq_*)
1204    SlotDef {
1205        name: "__len__",
1206        accessor: SlotAccessor::SqLength,
1207        op: None,
1208        doc: "__len__($self, /)\n--\n\nReturn len(self).",
1209    },
1210    SlotDef {
1211        name: "__getitem__",
1212        accessor: SlotAccessor::SqItem,
1213        op: None,
1214        doc: "__getitem__($self, key, /)\n--\n\nReturn self[key].",
1215    },
1216    SlotDef {
1217        name: "__setitem__",
1218        accessor: SlotAccessor::SqAssItem,
1219        op: None,
1220        doc: "__setitem__($self, key, value, /)\n--\n\nSet self[key] to value.",
1221    },
1222    SlotDef {
1223        name: "__delitem__",
1224        accessor: SlotAccessor::SqAssItem,
1225        op: Some(SlotOp::Delete),
1226        doc: "__delitem__($self, key, /)\n--\n\nDelete self[key].",
1227    },
1228    SlotDef {
1229        name: "__contains__",
1230        accessor: SlotAccessor::SqContains,
1231        op: None,
1232        doc: "__contains__($self, key, /)\n--\n\nReturn bool(key in self).",
1233    },
1234    // Number protocol - binary ops with left/right variants
1235    SlotDef {
1236        name: "__add__",
1237        accessor: SlotAccessor::NbAdd,
1238        op: Some(SlotOp::Left),
1239        doc: "__add__($self, value, /)\n--\n\nReturn self+value.",
1240    },
1241    SlotDef {
1242        name: "__radd__",
1243        accessor: SlotAccessor::NbAdd,
1244        op: Some(SlotOp::Right),
1245        doc: "__radd__($self, value, /)\n--\n\nReturn value+self.",
1246    },
1247    SlotDef {
1248        name: "__iadd__",
1249        accessor: SlotAccessor::NbInplaceAdd,
1250        op: None,
1251        doc: "__iadd__($self, value, /)\n--\n\nReturn self+=value.",
1252    },
1253    SlotDef {
1254        name: "__sub__",
1255        accessor: SlotAccessor::NbSubtract,
1256        op: Some(SlotOp::Left),
1257        doc: "__sub__($self, value, /)\n--\n\nReturn self-value.",
1258    },
1259    SlotDef {
1260        name: "__rsub__",
1261        accessor: SlotAccessor::NbSubtract,
1262        op: Some(SlotOp::Right),
1263        doc: "__rsub__($self, value, /)\n--\n\nReturn value-self.",
1264    },
1265    SlotDef {
1266        name: "__isub__",
1267        accessor: SlotAccessor::NbInplaceSubtract,
1268        op: None,
1269        doc: "__isub__($self, value, /)\n--\n\nReturn self-=value.",
1270    },
1271    SlotDef {
1272        name: "__mul__",
1273        accessor: SlotAccessor::NbMultiply,
1274        op: Some(SlotOp::Left),
1275        doc: "__mul__($self, value, /)\n--\n\nReturn self*value.",
1276    },
1277    SlotDef {
1278        name: "__rmul__",
1279        accessor: SlotAccessor::NbMultiply,
1280        op: Some(SlotOp::Right),
1281        doc: "__rmul__($self, value, /)\n--\n\nReturn value*self.",
1282    },
1283    SlotDef {
1284        name: "__imul__",
1285        accessor: SlotAccessor::NbInplaceMultiply,
1286        op: None,
1287        doc: "__imul__($self, value, /)\n--\n\nReturn self*=value.",
1288    },
1289    SlotDef {
1290        name: "__mod__",
1291        accessor: SlotAccessor::NbRemainder,
1292        op: Some(SlotOp::Left),
1293        doc: "__mod__($self, value, /)\n--\n\nReturn self%value.",
1294    },
1295    SlotDef {
1296        name: "__rmod__",
1297        accessor: SlotAccessor::NbRemainder,
1298        op: Some(SlotOp::Right),
1299        doc: "__rmod__($self, value, /)\n--\n\nReturn value%self.",
1300    },
1301    SlotDef {
1302        name: "__imod__",
1303        accessor: SlotAccessor::NbInplaceRemainder,
1304        op: None,
1305        doc: "__imod__($self, value, /)\n--\n\nReturn self%=value.",
1306    },
1307    SlotDef {
1308        name: "__divmod__",
1309        accessor: SlotAccessor::NbDivmod,
1310        op: Some(SlotOp::Left),
1311        doc: "__divmod__($self, value, /)\n--\n\nReturn divmod(self, value).",
1312    },
1313    SlotDef {
1314        name: "__rdivmod__",
1315        accessor: SlotAccessor::NbDivmod,
1316        op: Some(SlotOp::Right),
1317        doc: "__rdivmod__($self, value, /)\n--\n\nReturn divmod(value, self).",
1318    },
1319    SlotDef {
1320        name: "__pow__",
1321        accessor: SlotAccessor::NbPower,
1322        op: Some(SlotOp::Left),
1323        doc: "__pow__($self, value, mod=None, /)\n--\n\nReturn pow(self, value, mod).",
1324    },
1325    SlotDef {
1326        name: "__rpow__",
1327        accessor: SlotAccessor::NbPower,
1328        op: Some(SlotOp::Right),
1329        doc: "__rpow__($self, value, mod=None, /)\n--\n\nReturn pow(value, self, mod).",
1330    },
1331    SlotDef {
1332        name: "__ipow__",
1333        accessor: SlotAccessor::NbInplacePower,
1334        op: None,
1335        doc: "__ipow__($self, value, /)\n--\n\nReturn self**=value.",
1336    },
1337    SlotDef {
1338        name: "__lshift__",
1339        accessor: SlotAccessor::NbLshift,
1340        op: Some(SlotOp::Left),
1341        doc: "__lshift__($self, value, /)\n--\n\nReturn self<<value.",
1342    },
1343    SlotDef {
1344        name: "__rlshift__",
1345        accessor: SlotAccessor::NbLshift,
1346        op: Some(SlotOp::Right),
1347        doc: "__rlshift__($self, value, /)\n--\n\nReturn value<<self.",
1348    },
1349    SlotDef {
1350        name: "__ilshift__",
1351        accessor: SlotAccessor::NbInplaceLshift,
1352        op: None,
1353        doc: "__ilshift__($self, value, /)\n--\n\nReturn self<<=value.",
1354    },
1355    SlotDef {
1356        name: "__rshift__",
1357        accessor: SlotAccessor::NbRshift,
1358        op: Some(SlotOp::Left),
1359        doc: "__rshift__($self, value, /)\n--\n\nReturn self>>value.",
1360    },
1361    SlotDef {
1362        name: "__rrshift__",
1363        accessor: SlotAccessor::NbRshift,
1364        op: Some(SlotOp::Right),
1365        doc: "__rrshift__($self, value, /)\n--\n\nReturn value>>self.",
1366    },
1367    SlotDef {
1368        name: "__irshift__",
1369        accessor: SlotAccessor::NbInplaceRshift,
1370        op: None,
1371        doc: "__irshift__($self, value, /)\n--\n\nReturn self>>=value.",
1372    },
1373    SlotDef {
1374        name: "__and__",
1375        accessor: SlotAccessor::NbAnd,
1376        op: Some(SlotOp::Left),
1377        doc: "__and__($self, value, /)\n--\n\nReturn self&value.",
1378    },
1379    SlotDef {
1380        name: "__rand__",
1381        accessor: SlotAccessor::NbAnd,
1382        op: Some(SlotOp::Right),
1383        doc: "__rand__($self, value, /)\n--\n\nReturn value&self.",
1384    },
1385    SlotDef {
1386        name: "__iand__",
1387        accessor: SlotAccessor::NbInplaceAnd,
1388        op: None,
1389        doc: "__iand__($self, value, /)\n--\n\nReturn self&=value.",
1390    },
1391    SlotDef {
1392        name: "__xor__",
1393        accessor: SlotAccessor::NbXor,
1394        op: Some(SlotOp::Left),
1395        doc: "__xor__($self, value, /)\n--\n\nReturn self^value.",
1396    },
1397    SlotDef {
1398        name: "__rxor__",
1399        accessor: SlotAccessor::NbXor,
1400        op: Some(SlotOp::Right),
1401        doc: "__rxor__($self, value, /)\n--\n\nReturn value^self.",
1402    },
1403    SlotDef {
1404        name: "__ixor__",
1405        accessor: SlotAccessor::NbInplaceXor,
1406        op: None,
1407        doc: "__ixor__($self, value, /)\n--\n\nReturn self^=value.",
1408    },
1409    SlotDef {
1410        name: "__or__",
1411        accessor: SlotAccessor::NbOr,
1412        op: Some(SlotOp::Left),
1413        doc: "__or__($self, value, /)\n--\n\nReturn self|value.",
1414    },
1415    SlotDef {
1416        name: "__ror__",
1417        accessor: SlotAccessor::NbOr,
1418        op: Some(SlotOp::Right),
1419        doc: "__ror__($self, value, /)\n--\n\nReturn value|self.",
1420    },
1421    SlotDef {
1422        name: "__ior__",
1423        accessor: SlotAccessor::NbInplaceOr,
1424        op: None,
1425        doc: "__ior__($self, value, /)\n--\n\nReturn self|=value.",
1426    },
1427    SlotDef {
1428        name: "__floordiv__",
1429        accessor: SlotAccessor::NbFloorDivide,
1430        op: Some(SlotOp::Left),
1431        doc: "__floordiv__($self, value, /)\n--\n\nReturn self//value.",
1432    },
1433    SlotDef {
1434        name: "__rfloordiv__",
1435        accessor: SlotAccessor::NbFloorDivide,
1436        op: Some(SlotOp::Right),
1437        doc: "__rfloordiv__($self, value, /)\n--\n\nReturn value//self.",
1438    },
1439    SlotDef {
1440        name: "__ifloordiv__",
1441        accessor: SlotAccessor::NbInplaceFloorDivide,
1442        op: None,
1443        doc: "__ifloordiv__($self, value, /)\n--\n\nReturn self//=value.",
1444    },
1445    SlotDef {
1446        name: "__truediv__",
1447        accessor: SlotAccessor::NbTrueDivide,
1448        op: Some(SlotOp::Left),
1449        doc: "__truediv__($self, value, /)\n--\n\nReturn self/value.",
1450    },
1451    SlotDef {
1452        name: "__rtruediv__",
1453        accessor: SlotAccessor::NbTrueDivide,
1454        op: Some(SlotOp::Right),
1455        doc: "__rtruediv__($self, value, /)\n--\n\nReturn value/self.",
1456    },
1457    SlotDef {
1458        name: "__itruediv__",
1459        accessor: SlotAccessor::NbInplaceTrueDivide,
1460        op: None,
1461        doc: "__itruediv__($self, value, /)\n--\n\nReturn self/=value.",
1462    },
1463    SlotDef {
1464        name: "__matmul__",
1465        accessor: SlotAccessor::NbMatrixMultiply,
1466        op: Some(SlotOp::Left),
1467        doc: "__matmul__($self, value, /)\n--\n\nReturn self@value.",
1468    },
1469    SlotDef {
1470        name: "__rmatmul__",
1471        accessor: SlotAccessor::NbMatrixMultiply,
1472        op: Some(SlotOp::Right),
1473        doc: "__rmatmul__($self, value, /)\n--\n\nReturn value@self.",
1474    },
1475    SlotDef {
1476        name: "__imatmul__",
1477        accessor: SlotAccessor::NbInplaceMatrixMultiply,
1478        op: None,
1479        doc: "__imatmul__($self, value, /)\n--\n\nReturn self@=value.",
1480    },
1481    // Number unary operations
1482    SlotDef {
1483        name: "__neg__",
1484        accessor: SlotAccessor::NbNegative,
1485        op: None,
1486        doc: "__neg__($self, /)\n--\n\n-self",
1487    },
1488    SlotDef {
1489        name: "__pos__",
1490        accessor: SlotAccessor::NbPositive,
1491        op: None,
1492        doc: "__pos__($self, /)\n--\n\n+self",
1493    },
1494    SlotDef {
1495        name: "__abs__",
1496        accessor: SlotAccessor::NbAbsolute,
1497        op: None,
1498        doc: "__abs__($self, /)\n--\n\nabs(self)",
1499    },
1500    SlotDef {
1501        name: "__invert__",
1502        accessor: SlotAccessor::NbInvert,
1503        op: None,
1504        doc: "__invert__($self, /)\n--\n\n~self",
1505    },
1506    SlotDef {
1507        name: "__bool__",
1508        accessor: SlotAccessor::NbBool,
1509        op: None,
1510        doc: "__bool__($self, /)\n--\n\nTrue if self else False",
1511    },
1512    SlotDef {
1513        name: "__int__",
1514        accessor: SlotAccessor::NbInt,
1515        op: None,
1516        doc: "__int__($self, /)\n--\n\nint(self)",
1517    },
1518    SlotDef {
1519        name: "__float__",
1520        accessor: SlotAccessor::NbFloat,
1521        op: None,
1522        doc: "__float__($self, /)\n--\n\nfloat(self)",
1523    },
1524    SlotDef {
1525        name: "__index__",
1526        accessor: SlotAccessor::NbIndex,
1527        op: None,
1528        doc: "__index__($self, /)\n--\n\nReturn self converted to an integer, if self is suitable for use as an index into a list.",
1529    },
1530    // Sequence inplace operations (also map to number slots for some types)
1531    SlotDef {
1532        name: "__add__",
1533        accessor: SlotAccessor::SqConcat,
1534        op: None,
1535        doc: "__add__($self, value, /)\n--\n\nReturn self+value.",
1536    },
1537    SlotDef {
1538        name: "__mul__",
1539        accessor: SlotAccessor::SqRepeat,
1540        op: None,
1541        doc: "__mul__($self, value, /)\n--\n\nReturn self*value.",
1542    },
1543    SlotDef {
1544        name: "__rmul__",
1545        accessor: SlotAccessor::SqRepeat,
1546        op: None,
1547        doc: "__rmul__($self, value, /)\n--\n\nReturn value*self.",
1548    },
1549    SlotDef {
1550        name: "__iadd__",
1551        accessor: SlotAccessor::SqInplaceConcat,
1552        op: None,
1553        doc: "__iadd__($self, value, /)\n--\n\nImplement self+=value.",
1554    },
1555    SlotDef {
1556        name: "__imul__",
1557        accessor: SlotAccessor::SqInplaceRepeat,
1558        op: None,
1559        doc: "__imul__($self, value, /)\n--\n\nImplement self*=value.",
1560    },
1561];
1562
1563/// Total number of slot definitions.
1564pub const SLOT_DEFS_COUNT: usize = SLOT_DEFS.len();
1565
1566#[cfg(test)]
1567mod tests {
1568    use super::*;
1569
1570    #[test]
1571    fn find_by_name() {
1572        // __len__ appears in both sequence and mapping
1573        assert_eq!(find_slot_defs_by_name("__len__").count(), 2);
1574
1575        // __init__ appears once
1576        assert_eq!(find_slot_defs_by_name("__init__").count(), 1);
1577
1578        // __add__ appears in number (left/right) and sequence
1579        assert_eq!(find_slot_defs_by_name("__add__").count(), 2); // NbAdd(Left) and SqConcat
1580    }
1581
1582    #[test]
1583    fn slot_op() {
1584        // Test comparison ops
1585        assert_eq!(SlotOp::Lt.as_compare_op(), Some(PyComparisonOp::Lt));
1586        assert_eq!(SlotOp::Eq.as_compare_op(), Some(PyComparisonOp::Eq));
1587        assert_eq!(SlotOp::Left.as_compare_op(), None);
1588
1589        // Test right check
1590        assert!(SlotOp::Right.is_right());
1591        assert!(!SlotOp::Left.is_right());
1592    }
1593}