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