rustpython_vm/types/
slot.rs

1use crate::{
2    builtins::{type_::PointerSlot, PyInt, PyStr, PyStrInterned, PyStrRef, PyType, PyTypeRef},
3    bytecode::ComparisonOperator,
4    common::hash::PyHash,
5    convert::{ToPyObject, ToPyResult},
6    function::{
7        Either, FromArgs, FuncArgs, OptionalArg, PyComparisonValue, PyMethodDef, PySetterValue,
8    },
9    identifier,
10    protocol::{
11        PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyNumber, PyNumberMethods,
12        PyNumberSlots, PySequence, PySequenceMethods,
13    },
14    vm::Context,
15    AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
16};
17use crossbeam_utils::atomic::AtomicCell;
18use malachite_bigint::BigInt;
19use num_traits::{Signed, ToPrimitive};
20use std::{borrow::Borrow, cmp::Ordering, ops::Deref};
21
22#[macro_export]
23macro_rules! atomic_func {
24    ($x:expr) => {
25        crossbeam_utils::atomic::AtomicCell::new(Some($x))
26    };
27}
28
29// The corresponding field in CPython is `tp_` prefixed.
30// e.g. name -> tp_name
31#[derive(Default)]
32#[non_exhaustive]
33pub struct PyTypeSlots {
34    /// # Safety
35    /// For static types, always safe.
36    /// For heap types, `__name__` must alive
37    pub(crate) name: &'static str, // tp_name with <module>.<class> for print, not class name
38
39    pub basicsize: usize,
40    // tp_itemsize
41
42    // Methods to implement standard operations
43
44    // Method suites for standard classes
45    pub as_number: PyNumberSlots,
46    pub as_sequence: AtomicCell<Option<PointerSlot<PySequenceMethods>>>,
47    pub as_mapping: AtomicCell<Option<PointerSlot<PyMappingMethods>>>,
48
49    // More standard operations (here for binary compatibility)
50    pub hash: AtomicCell<Option<HashFunc>>,
51    pub call: AtomicCell<Option<GenericMethod>>,
52    // tp_str
53    pub repr: AtomicCell<Option<StringifyFunc>>,
54    pub getattro: AtomicCell<Option<GetattroFunc>>,
55    pub setattro: AtomicCell<Option<SetattroFunc>>,
56
57    // Functions to access object as input/output buffer
58    pub as_buffer: Option<AsBufferFunc>,
59
60    // Assigned meaning in release 2.1
61    // rich comparisons
62    pub richcompare: AtomicCell<Option<RichCompareFunc>>,
63
64    // Iterators
65    pub iter: AtomicCell<Option<IterFunc>>,
66    pub iternext: AtomicCell<Option<IterNextFunc>>,
67
68    pub methods: &'static [PyMethodDef],
69
70    // Flags to define presence of optional/expanded features
71    pub flags: PyTypeFlags,
72
73    // tp_doc
74    pub doc: Option<&'static str>,
75
76    // Strong reference on a heap type, borrowed reference on a static type
77    // tp_base
78    // tp_dict
79    pub descr_get: AtomicCell<Option<DescrGetFunc>>,
80    pub descr_set: AtomicCell<Option<DescrSetFunc>>,
81    // tp_dictoffset
82    pub init: AtomicCell<Option<InitFunc>>,
83    // tp_alloc
84    pub new: AtomicCell<Option<NewFunc>>,
85    // tp_free
86    // tp_is_gc
87    // tp_bases
88    // tp_mro
89    // tp_cache
90    // tp_subclasses
91    // tp_weaklist
92    pub del: AtomicCell<Option<DelFunc>>,
93
94    // The count of tp_members.
95    pub member_count: usize,
96}
97
98impl PyTypeSlots {
99    pub fn new(name: &'static str, flags: PyTypeFlags) -> Self {
100        Self {
101            name,
102            flags,
103            ..Default::default()
104        }
105    }
106
107    pub fn heap_default() -> Self {
108        Self {
109            // init: AtomicCell::new(Some(init_wrapper)),
110            ..Default::default()
111        }
112    }
113}
114
115impl std::fmt::Debug for PyTypeSlots {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        f.write_str("PyTypeSlots")
118    }
119}
120
121bitflags! {
122    #[derive(Copy, Clone, Debug, PartialEq)]
123    #[non_exhaustive]
124    pub struct PyTypeFlags: u64 {
125        const IMMUTABLETYPE = 1 << 8;
126        const HEAPTYPE = 1 << 9;
127        const BASETYPE = 1 << 10;
128        const METHOD_DESCRIPTOR = 1 << 17;
129        const HAS_DICT = 1 << 40;
130
131        #[cfg(debug_assertions)]
132        const _CREATED_WITH_FLAGS = 1 << 63;
133    }
134}
135
136impl PyTypeFlags {
137    // Default used for both built-in and normal classes: empty, for now.
138    // CPython default: Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | Py_TPFLAGS_HAVE_VERSION_TAG
139    pub const DEFAULT: Self = Self::empty();
140
141    // CPython: See initialization of flags in type_new.
142    /// Used for types created in Python. Subclassable and are a
143    /// heaptype.
144    pub const fn heap_type_flags() -> Self {
145        match Self::from_bits(Self::DEFAULT.bits() | Self::HEAPTYPE.bits() | Self::BASETYPE.bits())
146        {
147            Some(flags) => flags,
148            None => unreachable!(),
149        }
150    }
151
152    pub fn has_feature(self, flag: Self) -> bool {
153        self.contains(flag)
154    }
155
156    #[cfg(debug_assertions)]
157    pub fn is_created_with_flags(self) -> bool {
158        self.contains(Self::_CREATED_WITH_FLAGS)
159    }
160}
161
162impl Default for PyTypeFlags {
163    fn default() -> Self {
164        Self::DEFAULT
165    }
166}
167
168pub(crate) type GenericMethod = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyResult;
169pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyHash>;
170// CallFunc = GenericMethod
171pub(crate) type StringifyFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyStrRef>;
172pub(crate) type GetattroFunc = fn(&PyObject, &Py<PyStr>, &VirtualMachine) -> PyResult;
173pub(crate) type SetattroFunc =
174    fn(&PyObject, &Py<PyStr>, PySetterValue, &VirtualMachine) -> PyResult<()>;
175pub(crate) type AsBufferFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyBuffer>;
176pub(crate) type RichCompareFunc = fn(
177    &PyObject,
178    &PyObject,
179    PyComparisonOp,
180    &VirtualMachine,
181) -> PyResult<Either<PyObjectRef, PyComparisonValue>>;
182pub(crate) type IterFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult;
183pub(crate) type IterNextFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyIterReturn>;
184pub(crate) type DescrGetFunc =
185    fn(PyObjectRef, Option<PyObjectRef>, Option<PyObjectRef>, &VirtualMachine) -> PyResult;
186pub(crate) type DescrSetFunc =
187    fn(&PyObject, PyObjectRef, PySetterValue, &VirtualMachine) -> PyResult<()>;
188pub(crate) type NewFunc = fn(PyTypeRef, FuncArgs, &VirtualMachine) -> PyResult;
189pub(crate) type InitFunc = fn(PyObjectRef, FuncArgs, &VirtualMachine) -> PyResult<()>;
190pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>;
191
192// slot_sq_length
193pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult<usize> {
194    let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?;
195    let len = ret.payload::<PyInt>().ok_or_else(|| {
196        vm.new_type_error(format!(
197            "'{}' object cannot be interpreted as an integer",
198            ret.class()
199        ))
200    })?;
201    let len = len.as_bigint();
202    if len.is_negative() {
203        return Err(vm.new_value_error("__len__() should return >= 0".to_owned()));
204    }
205    let len = len.to_isize().ok_or_else(|| {
206        vm.new_overflow_error("cannot fit 'int' into an index-sized integer".to_owned())
207    })?;
208    Ok(len as usize)
209}
210
211pub(crate) fn contains_wrapper(
212    obj: &PyObject,
213    needle: &PyObject,
214    vm: &VirtualMachine,
215) -> PyResult<bool> {
216    let ret = vm.call_special_method(obj, identifier!(vm, __contains__), (needle,))?;
217    ret.try_to_bool(vm)
218}
219
220macro_rules! number_unary_op_wrapper {
221    ($name:ident) => {
222        |a, vm| vm.call_special_method(a.deref(), identifier!(vm, $name), ())
223    };
224}
225macro_rules! number_binary_op_wrapper {
226    ($name:ident) => {
227        |a, b, vm| vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(),))
228    };
229}
230macro_rules! number_binary_right_op_wrapper {
231    ($name:ident) => {
232        |a, b, vm| vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),))
233    };
234}
235fn getitem_wrapper<K: ToPyObject>(obj: &PyObject, needle: K, vm: &VirtualMachine) -> PyResult {
236    vm.call_special_method(obj, identifier!(vm, __getitem__), (needle,))
237}
238
239fn setitem_wrapper<K: ToPyObject>(
240    obj: &PyObject,
241    needle: K,
242    value: Option<PyObjectRef>,
243    vm: &VirtualMachine,
244) -> PyResult<()> {
245    match value {
246        Some(value) => vm.call_special_method(obj, identifier!(vm, __setitem__), (needle, value)),
247        None => vm.call_special_method(obj, identifier!(vm, __delitem__), (needle,)),
248    }
249    .map(drop)
250}
251
252fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyStrRef> {
253    let ret = vm.call_special_method(zelf, identifier!(vm, __repr__), ())?;
254    ret.downcast::<PyStr>().map_err(|obj| {
255        vm.new_type_error(format!(
256            "__repr__ returned non-string (type {})",
257            obj.class()
258        ))
259    })
260}
261
262fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
263    let hash_obj = vm.call_special_method(zelf, identifier!(vm, __hash__), ())?;
264    let py_int = hash_obj
265        .payload_if_subclass::<PyInt>(vm)
266        .ok_or_else(|| vm.new_type_error("__hash__ method should return an integer".to_owned()))?;
267    let big_int = py_int.as_bigint();
268    let hash: PyHash = big_int
269        .to_i64()
270        .unwrap_or_else(|| (big_int % BigInt::from(u64::MAX)).to_i64().unwrap());
271    Ok(hash)
272}
273
274/// Marks a type as unhashable. Similar to PyObject_HashNotImplemented in CPython
275pub fn hash_not_implemented(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
276    Err(vm.new_type_error(format!("unhashable type: {}", zelf.class().name())))
277}
278
279fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
280    vm.call_special_method(zelf, identifier!(vm, __call__), args)
281}
282
283fn getattro_wrapper(zelf: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
284    let __getattribute__ = identifier!(vm, __getattribute__);
285    let __getattr__ = identifier!(vm, __getattr__);
286    match vm.call_special_method(zelf, __getattribute__, (name.to_owned(),)) {
287        Ok(r) => Ok(r),
288        Err(_) if zelf.class().has_attr(__getattr__) => {
289            vm.call_special_method(zelf, __getattr__, (name.to_owned(),))
290        }
291        Err(e) => Err(e),
292    }
293}
294
295fn setattro_wrapper(
296    zelf: &PyObject,
297    name: &Py<PyStr>,
298    value: PySetterValue,
299    vm: &VirtualMachine,
300) -> PyResult<()> {
301    let name = name.to_owned();
302    match value {
303        PySetterValue::Assign(value) => {
304            vm.call_special_method(zelf, identifier!(vm, __setattr__), (name, value))?;
305        }
306        PySetterValue::Delete => {
307            vm.call_special_method(zelf, identifier!(vm, __delattr__), (name,))?;
308        }
309    };
310    Ok(())
311}
312
313pub(crate) fn richcompare_wrapper(
314    zelf: &PyObject,
315    other: &PyObject,
316    op: PyComparisonOp,
317    vm: &VirtualMachine,
318) -> PyResult<Either<PyObjectRef, PyComparisonValue>> {
319    vm.call_special_method(zelf, op.method_name(&vm.ctx), (other.to_owned(),))
320        .map(Either::A)
321}
322
323fn iter_wrapper(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
324    vm.call_special_method(&zelf, identifier!(vm, __iter__), ())
325}
326
327// PyObject_SelfIter in CPython
328fn self_iter(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult {
329    Ok(zelf)
330}
331
332fn iternext_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
333    PyIterReturn::from_pyresult(
334        vm.call_special_method(zelf, identifier!(vm, __next__), ()),
335        vm,
336    )
337}
338
339fn descr_get_wrapper(
340    zelf: PyObjectRef,
341    obj: Option<PyObjectRef>,
342    cls: Option<PyObjectRef>,
343    vm: &VirtualMachine,
344) -> PyResult {
345    vm.call_special_method(&zelf, identifier!(vm, __get__), (obj, cls))
346}
347
348fn descr_set_wrapper(
349    zelf: &PyObject,
350    obj: PyObjectRef,
351    value: PySetterValue,
352    vm: &VirtualMachine,
353) -> PyResult<()> {
354    match value {
355        PySetterValue::Assign(val) => {
356            vm.call_special_method(zelf, identifier!(vm, __set__), (obj, val))
357        }
358        PySetterValue::Delete => vm.call_special_method(zelf, identifier!(vm, __delete__), (obj,)),
359    }
360    .map(drop)
361}
362
363fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
364    let res = vm.call_special_method(&obj, identifier!(vm, __init__), args)?;
365    if !vm.is_none(&res) {
366        return Err(vm.new_type_error("__init__ must return None".to_owned()));
367    }
368    Ok(())
369}
370
371pub(crate) fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
372    let new = cls.get_attr(identifier!(vm, __new__)).unwrap();
373    args.prepend_arg(cls.into());
374    new.call(args, vm)
375}
376
377fn del_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
378    vm.call_special_method(zelf, identifier!(vm, __del__), ())?;
379    Ok(())
380}
381
382impl PyType {
383    pub(crate) fn update_slot<const ADD: bool>(&self, name: &'static PyStrInterned, ctx: &Context) {
384        debug_assert!(name.as_str().starts_with("__"));
385        debug_assert!(name.as_str().ends_with("__"));
386
387        macro_rules! toggle_slot {
388            ($name:ident, $func:expr) => {{
389                self.slots.$name.store(if ADD { Some($func) } else { None });
390            }};
391        }
392
393        macro_rules! toggle_subslot {
394            ($group:ident, $name:ident, $func:expr) => {
395                self.slots
396                    .$group
397                    .$name
398                    .store(if ADD { Some($func) } else { None });
399            };
400        }
401
402        macro_rules! update_slot {
403            ($name:ident, $func:expr) => {{
404                self.slots.$name.store(Some($func));
405            }};
406        }
407
408        macro_rules! update_pointer_slot {
409            ($name:ident, $pointed:ident) => {{
410                self.slots
411                    .$name
412                    .store(unsafe { PointerSlot::from_heaptype(self, |ext| &ext.$pointed) });
413            }};
414        }
415
416        macro_rules! toggle_ext_func {
417            ($n1:ident, $n2:ident, $func:expr) => {{
418                self.heaptype_ext.as_ref().unwrap().$n1.$n2.store(if ADD {
419                    Some($func)
420                } else {
421                    None
422                });
423            }};
424        }
425
426        match name {
427            _ if name == identifier!(ctx, __len__) => {
428                // update_slot!(as_mapping, slot_as_mapping);
429                toggle_ext_func!(sequence_methods, length, |seq, vm| len_wrapper(seq.obj, vm));
430                update_pointer_slot!(as_sequence, sequence_methods);
431                toggle_ext_func!(mapping_methods, length, |mapping, vm| len_wrapper(
432                    mapping.obj,
433                    vm
434                ));
435                update_pointer_slot!(as_mapping, mapping_methods);
436            }
437            _ if name == identifier!(ctx, __getitem__) => {
438                // update_slot!(as_mapping, slot_as_mapping);
439                toggle_ext_func!(sequence_methods, item, |seq, i, vm| getitem_wrapper(
440                    seq.obj, i, vm
441                ));
442                update_pointer_slot!(as_sequence, sequence_methods);
443                toggle_ext_func!(mapping_methods, subscript, |mapping, key, vm| {
444                    getitem_wrapper(mapping.obj, key, vm)
445                });
446                update_pointer_slot!(as_mapping, mapping_methods);
447            }
448            _ if name == identifier!(ctx, __setitem__) || name == identifier!(ctx, __delitem__) => {
449                // update_slot!(as_mapping, slot_as_mapping);
450                toggle_ext_func!(sequence_methods, ass_item, |seq, i, value, vm| {
451                    setitem_wrapper(seq.obj, i, value, vm)
452                });
453                update_pointer_slot!(as_sequence, sequence_methods);
454                toggle_ext_func!(mapping_methods, ass_subscript, |mapping, key, value, vm| {
455                    setitem_wrapper(mapping.obj, key, value, vm)
456                });
457                update_pointer_slot!(as_mapping, mapping_methods);
458            }
459            _ if name == identifier!(ctx, __contains__) => {
460                toggle_ext_func!(sequence_methods, contains, |seq, needle, vm| {
461                    contains_wrapper(seq.obj, needle, vm)
462                });
463                update_pointer_slot!(as_sequence, sequence_methods);
464            }
465            _ if name == identifier!(ctx, __repr__) => {
466                update_slot!(repr, repr_wrapper);
467            }
468            _ if name == identifier!(ctx, __hash__) => {
469                let is_unhashable = self
470                    .attributes
471                    .read()
472                    .get(identifier!(ctx, __hash__))
473                    .map_or(false, |a| a.is(&ctx.none));
474                let wrapper = if is_unhashable {
475                    hash_not_implemented
476                } else {
477                    hash_wrapper
478                };
479                toggle_slot!(hash, wrapper);
480            }
481            _ if name == identifier!(ctx, __call__) => {
482                toggle_slot!(call, call_wrapper);
483            }
484            _ if name == identifier!(ctx, __getattr__)
485                || name == identifier!(ctx, __getattribute__) =>
486            {
487                update_slot!(getattro, getattro_wrapper);
488            }
489            _ if name == identifier!(ctx, __setattr__) || name == identifier!(ctx, __delattr__) => {
490                update_slot!(setattro, setattro_wrapper);
491            }
492            _ if name == identifier!(ctx, __eq__)
493                || name == identifier!(ctx, __ne__)
494                || name == identifier!(ctx, __le__)
495                || name == identifier!(ctx, __lt__)
496                || name == identifier!(ctx, __ge__)
497                || name == identifier!(ctx, __gt__) =>
498            {
499                update_slot!(richcompare, richcompare_wrapper);
500            }
501            _ if name == identifier!(ctx, __iter__) => {
502                toggle_slot!(iter, iter_wrapper);
503            }
504            _ if name == identifier!(ctx, __next__) => {
505                toggle_slot!(iternext, iternext_wrapper);
506            }
507            _ if name == identifier!(ctx, __get__) => {
508                toggle_slot!(descr_get, descr_get_wrapper);
509            }
510            _ if name == identifier!(ctx, __set__) || name == identifier!(ctx, __delete__) => {
511                update_slot!(descr_set, descr_set_wrapper);
512            }
513            _ if name == identifier!(ctx, __init__) => {
514                toggle_slot!(init, init_wrapper);
515            }
516            _ if name == identifier!(ctx, __new__) => {
517                toggle_slot!(new, new_wrapper);
518            }
519            _ if name == identifier!(ctx, __del__) => {
520                toggle_slot!(del, del_wrapper);
521            }
522            _ if name == identifier!(ctx, __int__) => {
523                toggle_subslot!(as_number, int, number_unary_op_wrapper!(__int__));
524            }
525            _ if name == identifier!(ctx, __index__) => {
526                toggle_subslot!(as_number, index, number_unary_op_wrapper!(__index__));
527            }
528            _ if name == identifier!(ctx, __float__) => {
529                toggle_subslot!(as_number, float, number_unary_op_wrapper!(__float__));
530            }
531            _ if name == identifier!(ctx, __add__) => {
532                toggle_subslot!(as_number, add, number_binary_op_wrapper!(__add__));
533            }
534            _ if name == identifier!(ctx, __radd__) => {
535                toggle_subslot!(
536                    as_number,
537                    right_add,
538                    number_binary_right_op_wrapper!(__radd__)
539                );
540            }
541            _ if name == identifier!(ctx, __iadd__) => {
542                toggle_subslot!(as_number, inplace_add, number_binary_op_wrapper!(__iadd__));
543            }
544            _ if name == identifier!(ctx, __sub__) => {
545                toggle_subslot!(as_number, subtract, number_binary_op_wrapper!(__sub__));
546            }
547            _ if name == identifier!(ctx, __rsub__) => {
548                toggle_subslot!(
549                    as_number,
550                    right_subtract,
551                    number_binary_right_op_wrapper!(__rsub__)
552                );
553            }
554            _ if name == identifier!(ctx, __isub__) => {
555                toggle_subslot!(
556                    as_number,
557                    inplace_subtract,
558                    number_binary_op_wrapper!(__isub__)
559                );
560            }
561            _ if name == identifier!(ctx, __mul__) => {
562                toggle_subslot!(as_number, multiply, number_binary_op_wrapper!(__mul__));
563            }
564            _ if name == identifier!(ctx, __rmul__) => {
565                toggle_subslot!(
566                    as_number,
567                    right_multiply,
568                    number_binary_right_op_wrapper!(__rmul__)
569                );
570            }
571            _ if name == identifier!(ctx, __imul__) => {
572                toggle_subslot!(
573                    as_number,
574                    inplace_multiply,
575                    number_binary_op_wrapper!(__imul__)
576                );
577            }
578            _ if name == identifier!(ctx, __mod__) => {
579                toggle_subslot!(as_number, remainder, number_binary_op_wrapper!(__mod__));
580            }
581            _ if name == identifier!(ctx, __rmod__) => {
582                toggle_subslot!(
583                    as_number,
584                    right_remainder,
585                    number_binary_right_op_wrapper!(__rmod__)
586                );
587            }
588            _ if name == identifier!(ctx, __imod__) => {
589                toggle_subslot!(
590                    as_number,
591                    inplace_remainder,
592                    number_binary_op_wrapper!(__imod__)
593                );
594            }
595            _ if name == identifier!(ctx, __divmod__) => {
596                toggle_subslot!(as_number, divmod, number_binary_op_wrapper!(__divmod__));
597            }
598            _ if name == identifier!(ctx, __rdivmod__) => {
599                toggle_subslot!(
600                    as_number,
601                    right_divmod,
602                    number_binary_right_op_wrapper!(__rdivmod__)
603                );
604            }
605            _ if name == identifier!(ctx, __pow__) => {
606                toggle_subslot!(as_number, power, |a, b, c, vm| {
607                    let args = if vm.is_none(c) {
608                        vec![b.to_owned()]
609                    } else {
610                        vec![b.to_owned(), c.to_owned()]
611                    };
612                    vm.call_special_method(a, identifier!(vm, __pow__), args)
613                });
614            }
615            _ if name == identifier!(ctx, __rpow__) => {
616                toggle_subslot!(as_number, right_power, |a, b, c, vm| {
617                    let args = if vm.is_none(c) {
618                        vec![a.to_owned()]
619                    } else {
620                        vec![a.to_owned(), c.to_owned()]
621                    };
622                    vm.call_special_method(b, identifier!(vm, __rpow__), args)
623                });
624            }
625            _ if name == identifier!(ctx, __ipow__) => {
626                toggle_subslot!(as_number, inplace_power, |a, b, _, vm| {
627                    vm.call_special_method(a, identifier!(vm, __ipow__), (b.to_owned(),))
628                });
629            }
630            _ if name == identifier!(ctx, __lshift__) => {
631                toggle_subslot!(as_number, lshift, number_binary_op_wrapper!(__lshift__));
632            }
633            _ if name == identifier!(ctx, __rlshift__) => {
634                toggle_subslot!(
635                    as_number,
636                    right_lshift,
637                    number_binary_right_op_wrapper!(__rlshift__)
638                );
639            }
640            _ if name == identifier!(ctx, __ilshift__) => {
641                toggle_subslot!(
642                    as_number,
643                    inplace_lshift,
644                    number_binary_op_wrapper!(__ilshift__)
645                );
646            }
647            _ if name == identifier!(ctx, __rshift__) => {
648                toggle_subslot!(as_number, rshift, number_binary_op_wrapper!(__rshift__));
649            }
650            _ if name == identifier!(ctx, __rrshift__) => {
651                toggle_subslot!(
652                    as_number,
653                    right_rshift,
654                    number_binary_right_op_wrapper!(__rrshift__)
655                );
656            }
657            _ if name == identifier!(ctx, __irshift__) => {
658                toggle_subslot!(
659                    as_number,
660                    inplace_rshift,
661                    number_binary_op_wrapper!(__irshift__)
662                );
663            }
664            _ if name == identifier!(ctx, __and__) => {
665                toggle_subslot!(as_number, and, number_binary_op_wrapper!(__and__));
666            }
667            _ if name == identifier!(ctx, __rand__) => {
668                toggle_subslot!(
669                    as_number,
670                    right_and,
671                    number_binary_right_op_wrapper!(__rand__)
672                );
673            }
674            _ if name == identifier!(ctx, __iand__) => {
675                toggle_subslot!(as_number, inplace_and, number_binary_op_wrapper!(__iand__));
676            }
677            _ if name == identifier!(ctx, __xor__) => {
678                toggle_subslot!(as_number, xor, number_binary_op_wrapper!(__xor__));
679            }
680            _ if name == identifier!(ctx, __rxor__) => {
681                toggle_subslot!(
682                    as_number,
683                    right_xor,
684                    number_binary_right_op_wrapper!(__rxor__)
685                );
686            }
687            _ if name == identifier!(ctx, __ixor__) => {
688                toggle_subslot!(as_number, inplace_xor, number_binary_op_wrapper!(__ixor__));
689            }
690            _ if name == identifier!(ctx, __or__) => {
691                toggle_subslot!(as_number, or, number_binary_op_wrapper!(__or__));
692            }
693            _ if name == identifier!(ctx, __ror__) => {
694                toggle_subslot!(
695                    as_number,
696                    right_or,
697                    number_binary_right_op_wrapper!(__ror__)
698                );
699            }
700            _ if name == identifier!(ctx, __ior__) => {
701                toggle_subslot!(as_number, inplace_or, number_binary_op_wrapper!(__ior__));
702            }
703            _ if name == identifier!(ctx, __floordiv__) => {
704                toggle_subslot!(
705                    as_number,
706                    floor_divide,
707                    number_binary_op_wrapper!(__floordiv__)
708                );
709            }
710            _ if name == identifier!(ctx, __rfloordiv__) => {
711                toggle_subslot!(
712                    as_number,
713                    right_floor_divide,
714                    number_binary_right_op_wrapper!(__rfloordiv__)
715                );
716            }
717            _ if name == identifier!(ctx, __ifloordiv__) => {
718                toggle_subslot!(
719                    as_number,
720                    inplace_floor_divide,
721                    number_binary_op_wrapper!(__ifloordiv__)
722                );
723            }
724            _ if name == identifier!(ctx, __truediv__) => {
725                toggle_subslot!(
726                    as_number,
727                    true_divide,
728                    number_binary_op_wrapper!(__truediv__)
729                );
730            }
731            _ if name == identifier!(ctx, __rtruediv__) => {
732                toggle_subslot!(
733                    as_number,
734                    right_true_divide,
735                    number_binary_right_op_wrapper!(__rtruediv__)
736                );
737            }
738            _ if name == identifier!(ctx, __itruediv__) => {
739                toggle_subslot!(
740                    as_number,
741                    inplace_true_divide,
742                    number_binary_op_wrapper!(__itruediv__)
743                );
744            }
745            _ if name == identifier!(ctx, __matmul__) => {
746                toggle_subslot!(
747                    as_number,
748                    matrix_multiply,
749                    number_binary_op_wrapper!(__matmul__)
750                );
751            }
752            _ if name == identifier!(ctx, __rmatmul__) => {
753                toggle_subslot!(
754                    as_number,
755                    right_matrix_multiply,
756                    number_binary_right_op_wrapper!(__rmatmul__)
757                );
758            }
759            _ if name == identifier!(ctx, __imatmul__) => {
760                toggle_subslot!(
761                    as_number,
762                    inplace_matrix_multiply,
763                    number_binary_op_wrapper!(__imatmul__)
764                );
765            }
766            _ => {}
767        }
768    }
769}
770
771#[pyclass]
772pub trait Constructor: PyPayload {
773    type Args: FromArgs;
774
775    #[inline]
776    #[pyslot]
777    fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
778        let args: Self::Args = args.bind(vm)?;
779        Self::py_new(cls, args, vm)
780    }
781
782    fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult;
783}
784
785pub trait DefaultConstructor: PyPayload + Default {}
786
787/// For types that cannot be instantiated through Python code.
788#[pyclass]
789pub trait Unconstructible: PyPayload {
790    #[pyslot]
791    fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
792        Err(vm.new_type_error(format!("cannot create {} instances", cls.slot_name())))
793    }
794}
795
796impl<T> Constructor for T
797where
798    T: DefaultConstructor,
799{
800    type Args = FuncArgs;
801
802    fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
803        Self::default().into_ref_with_type(vm, cls).map(Into::into)
804    }
805
806    fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult {
807        Err(vm.new_type_error(format!("cannot create {} instances", cls.slot_name())))
808    }
809}
810
811#[pyclass]
812pub trait Initializer: PyPayload {
813    type Args: FromArgs;
814
815    #[pyslot]
816    #[inline]
817    fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
818        let zelf = zelf.try_into_value(vm)?;
819        let args: Self::Args = args.bind(vm)?;
820        Self::init(zelf, args, vm)
821    }
822
823    #[pymethod]
824    #[inline]
825    fn __init__(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
826        Self::init(zelf, args, vm)
827    }
828
829    fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()>;
830}
831
832#[pyclass]
833pub trait Destructor: PyPayload {
834    #[inline] // for __del__
835    #[pyslot]
836    fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
837        let zelf = zelf
838            .downcast_ref()
839            .ok_or_else(|| vm.new_type_error("unexpected payload for __del__".to_owned()))?;
840        Self::del(zelf, vm)
841    }
842
843    #[pymethod]
844    fn __del__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
845        Self::slot_del(&zelf, vm)
846    }
847
848    fn del(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<()>;
849}
850
851#[pyclass]
852pub trait Callable: PyPayload {
853    type Args: FromArgs;
854
855    #[inline]
856    #[pyslot]
857    fn slot_call(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
858        let zelf = zelf.downcast_ref().ok_or_else(|| {
859            let repr = zelf.repr(vm);
860            let help = if let Ok(repr) = repr.as_ref() {
861                repr.as_str().to_owned()
862            } else {
863                zelf.class().name().to_owned()
864            };
865            vm.new_type_error(format!("unexpected payload for __call__ of {help}"))
866        })?;
867        let args = args.bind(vm)?;
868        Self::call(zelf, args, vm)
869    }
870
871    #[inline]
872    #[pymethod]
873    fn __call__(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
874        Self::slot_call(&zelf, args.bind(vm)?, vm)
875    }
876    fn call(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult;
877}
878
879#[pyclass]
880pub trait GetDescriptor: PyPayload {
881    #[pyslot]
882    fn descr_get(
883        zelf: PyObjectRef,
884        obj: Option<PyObjectRef>,
885        cls: Option<PyObjectRef>,
886        vm: &VirtualMachine,
887    ) -> PyResult;
888
889    #[inline]
890    #[pymethod(magic)]
891    fn get(
892        zelf: PyObjectRef,
893        obj: PyObjectRef,
894        cls: OptionalArg<PyObjectRef>,
895        vm: &VirtualMachine,
896    ) -> PyResult {
897        Self::descr_get(zelf, Some(obj), cls.into_option(), vm)
898    }
899
900    #[inline]
901    fn _as_pyref<'a>(zelf: &'a PyObject, vm: &VirtualMachine) -> PyResult<&'a Py<Self>> {
902        zelf.try_to_value(vm)
903    }
904
905    #[inline]
906    fn _unwrap<'a>(
907        zelf: &'a PyObject,
908        obj: Option<PyObjectRef>,
909        vm: &VirtualMachine,
910    ) -> PyResult<(&'a Py<Self>, PyObjectRef)> {
911        let zelf = Self::_as_pyref(zelf, vm)?;
912        let obj = vm.unwrap_or_none(obj);
913        Ok((zelf, obj))
914    }
915
916    #[inline]
917    fn _check<'a>(
918        zelf: &'a PyObject,
919        obj: Option<PyObjectRef>,
920        vm: &VirtualMachine,
921    ) -> Option<(&'a Py<Self>, PyObjectRef)> {
922        // CPython descr_check
923        let obj = obj?;
924        // if (!PyObject_TypeCheck(obj, descr->d_type)) {
925        //     PyErr_Format(PyExc_TypeError,
926        //                  "descriptor '%V' for '%.100s' objects "
927        //                  "doesn't apply to a '%.100s' object",
928        //                  descr_name((PyDescrObject *)descr), "?",
929        //                  descr->d_type->slot_name,
930        //                  obj->ob_type->slot_name);
931        //     *pres = NULL;
932        //     return 1;
933        // } else {
934        Some((Self::_as_pyref(zelf, vm).unwrap(), obj))
935    }
936
937    #[inline]
938    fn _cls_is(cls: &Option<PyObjectRef>, other: &impl Borrow<PyObject>) -> bool {
939        cls.as_ref().map_or(false, |cls| other.borrow().is(cls))
940    }
941}
942
943#[pyclass]
944pub trait Hashable: PyPayload {
945    #[inline]
946    #[pyslot]
947    fn slot_hash(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
948        let zelf = zelf
949            .downcast_ref()
950            .ok_or_else(|| vm.new_type_error("unexpected payload for __hash__".to_owned()))?;
951        Self::hash(zelf, vm)
952    }
953
954    #[inline]
955    #[pymethod]
956    fn __hash__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyHash> {
957        Self::slot_hash(&zelf, vm)
958    }
959
960    fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash>;
961}
962
963#[pyclass]
964pub trait Representable: PyPayload {
965    #[inline]
966    #[pyslot]
967    fn slot_repr(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyStrRef> {
968        let zelf = zelf
969            .downcast_ref()
970            .ok_or_else(|| vm.new_type_error("unexpected payload for __repr__".to_owned()))?;
971        Self::repr(zelf, vm)
972    }
973
974    #[inline]
975    #[pymethod]
976    fn __repr__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
977        Self::slot_repr(&zelf, vm)
978    }
979
980    #[inline]
981    fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
982        let repr = Self::repr_str(zelf, vm)?;
983        Ok(vm.ctx.new_str(repr))
984    }
985
986    fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String>;
987}
988
989#[pyclass]
990pub trait Comparable: PyPayload {
991    #[inline]
992    #[pyslot]
993    fn slot_richcompare(
994        zelf: &PyObject,
995        other: &PyObject,
996        op: PyComparisonOp,
997        vm: &VirtualMachine,
998    ) -> PyResult<Either<PyObjectRef, PyComparisonValue>> {
999        let zelf = zelf.downcast_ref().ok_or_else(|| {
1000            vm.new_type_error(format!(
1001                "unexpected payload for {}",
1002                op.method_name(&vm.ctx).as_str()
1003            ))
1004        })?;
1005        Self::cmp(zelf, other, op, vm).map(Either::B)
1006    }
1007
1008    fn cmp(
1009        zelf: &Py<Self>,
1010        other: &PyObject,
1011        op: PyComparisonOp,
1012        vm: &VirtualMachine,
1013    ) -> PyResult<PyComparisonValue>;
1014
1015    #[inline]
1016    #[pymethod(magic)]
1017    fn eq(zelf: &Py<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
1018        Self::cmp(zelf, &other, PyComparisonOp::Eq, vm)
1019    }
1020    #[inline]
1021    #[pymethod(magic)]
1022    fn ne(zelf: &Py<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
1023        Self::cmp(zelf, &other, PyComparisonOp::Ne, vm)
1024    }
1025    #[inline]
1026    #[pymethod(magic)]
1027    fn lt(zelf: &Py<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
1028        Self::cmp(zelf, &other, PyComparisonOp::Lt, vm)
1029    }
1030    #[inline]
1031    #[pymethod(magic)]
1032    fn le(zelf: &Py<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
1033        Self::cmp(zelf, &other, PyComparisonOp::Le, vm)
1034    }
1035    #[inline]
1036    #[pymethod(magic)]
1037    fn ge(zelf: &Py<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
1038        Self::cmp(zelf, &other, PyComparisonOp::Ge, vm)
1039    }
1040    #[inline]
1041    #[pymethod(magic)]
1042    fn gt(zelf: &Py<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyComparisonValue> {
1043        Self::cmp(zelf, &other, PyComparisonOp::Gt, vm)
1044    }
1045}
1046
1047#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1048#[repr(transparent)]
1049pub struct PyComparisonOp(ComparisonOperator);
1050
1051impl From<ComparisonOperator> for PyComparisonOp {
1052    fn from(op: ComparisonOperator) -> Self {
1053        Self(op)
1054    }
1055}
1056
1057#[allow(non_upper_case_globals)]
1058impl PyComparisonOp {
1059    pub const Lt: Self = Self(ComparisonOperator::Less);
1060    pub const Gt: Self = Self(ComparisonOperator::Greater);
1061    pub const Ne: Self = Self(ComparisonOperator::NotEqual);
1062    pub const Eq: Self = Self(ComparisonOperator::Equal);
1063    pub const Le: Self = Self(ComparisonOperator::LessOrEqual);
1064    pub const Ge: Self = Self(ComparisonOperator::GreaterOrEqual);
1065}
1066
1067impl PyComparisonOp {
1068    pub fn eq_only(
1069        self,
1070        f: impl FnOnce() -> PyResult<PyComparisonValue>,
1071    ) -> PyResult<PyComparisonValue> {
1072        match self {
1073            Self::Eq => f(),
1074            Self::Ne => f().map(|x| x.map(|eq| !eq)),
1075            _ => Ok(PyComparisonValue::NotImplemented),
1076        }
1077    }
1078
1079    pub fn eval_ord(self, ord: Ordering) -> bool {
1080        let bit = match ord {
1081            Ordering::Less => Self::Lt,
1082            Ordering::Equal => Self::Eq,
1083            Ordering::Greater => Self::Gt,
1084        };
1085        self.0 as u8 & bit.0 as u8 != 0
1086    }
1087
1088    pub fn swapped(self) -> Self {
1089        match self {
1090            Self::Lt => Self::Gt,
1091            Self::Le => Self::Ge,
1092            Self::Eq => Self::Eq,
1093            Self::Ne => Self::Ne,
1094            Self::Ge => Self::Le,
1095            Self::Gt => Self::Lt,
1096        }
1097    }
1098
1099    pub fn method_name(self, ctx: &Context) -> &'static PyStrInterned {
1100        match self {
1101            Self::Lt => identifier!(ctx, __lt__),
1102            Self::Le => identifier!(ctx, __le__),
1103            Self::Eq => identifier!(ctx, __eq__),
1104            Self::Ne => identifier!(ctx, __ne__),
1105            Self::Ge => identifier!(ctx, __ge__),
1106            Self::Gt => identifier!(ctx, __gt__),
1107        }
1108    }
1109
1110    pub fn operator_token(self) -> &'static str {
1111        match self {
1112            Self::Lt => "<",
1113            Self::Le => "<=",
1114            Self::Eq => "==",
1115            Self::Ne => "!=",
1116            Self::Ge => ">=",
1117            Self::Gt => ">",
1118        }
1119    }
1120
1121    /// Returns an appropriate return value for the comparison when a and b are the same object, if an
1122    /// appropriate return value exists.
1123    #[inline]
1124    pub fn identical_optimization(
1125        self,
1126        a: &impl Borrow<PyObject>,
1127        b: &impl Borrow<PyObject>,
1128    ) -> Option<bool> {
1129        self.map_eq(|| a.borrow().is(b.borrow()))
1130    }
1131
1132    /// Returns `Some(true)` when self is `Eq` and `f()` returns true. Returns `Some(false)` when self
1133    /// is `Ne` and `f()` returns true. Otherwise returns `None`.
1134    #[inline]
1135    pub fn map_eq(self, f: impl FnOnce() -> bool) -> Option<bool> {
1136        let eq = match self {
1137            Self::Eq => true,
1138            Self::Ne => false,
1139            _ => return None,
1140        };
1141        f().then_some(eq)
1142    }
1143}
1144
1145#[pyclass]
1146pub trait GetAttr: PyPayload {
1147    #[pyslot]
1148    fn slot_getattro(obj: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
1149        let zelf = obj.downcast_ref().ok_or_else(|| {
1150            vm.new_type_error("unexpected payload for __getattribute__".to_owned())
1151        })?;
1152        Self::getattro(zelf, name, vm)
1153    }
1154
1155    fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult;
1156
1157    #[inline]
1158    #[pymethod(magic)]
1159    fn getattribute(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
1160        Self::getattro(&zelf, &name, vm)
1161    }
1162}
1163
1164#[pyclass]
1165pub trait SetAttr: PyPayload {
1166    #[pyslot]
1167    #[inline]
1168    fn slot_setattro(
1169        obj: &PyObject,
1170        name: &Py<PyStr>,
1171        value: PySetterValue,
1172        vm: &VirtualMachine,
1173    ) -> PyResult<()> {
1174        let zelf = obj
1175            .downcast_ref::<Self>()
1176            .ok_or_else(|| vm.new_type_error("unexpected payload for __setattr__".to_owned()))?;
1177        Self::setattro(zelf, name, value, vm)
1178    }
1179
1180    fn setattro(
1181        zelf: &Py<Self>,
1182        name: &Py<PyStr>,
1183        value: PySetterValue,
1184        vm: &VirtualMachine,
1185    ) -> PyResult<()>;
1186
1187    #[inline]
1188    #[pymethod(magic)]
1189    fn setattr(
1190        zelf: PyRef<Self>,
1191        name: PyStrRef,
1192        value: PyObjectRef,
1193        vm: &VirtualMachine,
1194    ) -> PyResult<()> {
1195        Self::setattro(&zelf, &name, PySetterValue::Assign(value), vm)
1196    }
1197
1198    #[inline]
1199    #[pymethod(magic)]
1200    fn delattr(zelf: PyRef<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
1201        Self::setattro(&zelf, &name, PySetterValue::Delete, vm)
1202    }
1203}
1204
1205#[pyclass]
1206pub trait AsBuffer: PyPayload {
1207    // TODO: `flags` parameter
1208    #[inline]
1209    #[pyslot]
1210    fn slot_as_buffer(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyBuffer> {
1211        let zelf = zelf
1212            .downcast_ref()
1213            .ok_or_else(|| vm.new_type_error("unexpected payload for as_buffer".to_owned()))?;
1214        Self::as_buffer(zelf, vm)
1215    }
1216
1217    fn as_buffer(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyBuffer>;
1218}
1219
1220#[pyclass]
1221pub trait AsMapping: PyPayload {
1222    #[pyslot]
1223    fn as_mapping() -> &'static PyMappingMethods;
1224
1225    #[inline]
1226    fn mapping_downcast(mapping: PyMapping) -> &Py<Self> {
1227        unsafe { mapping.obj.downcast_unchecked_ref() }
1228    }
1229}
1230
1231#[pyclass]
1232pub trait AsSequence: PyPayload {
1233    #[pyslot]
1234    fn as_sequence() -> &'static PySequenceMethods;
1235
1236    #[inline]
1237    fn sequence_downcast(seq: PySequence) -> &Py<Self> {
1238        unsafe { seq.obj.downcast_unchecked_ref() }
1239    }
1240}
1241
1242#[pyclass]
1243pub trait AsNumber: PyPayload {
1244    #[pyslot]
1245    fn as_number() -> &'static PyNumberMethods;
1246
1247    fn clone_exact(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
1248        // not all AsNumber requires this implementation.
1249        unimplemented!()
1250    }
1251
1252    #[inline]
1253    fn number_downcast(num: PyNumber) -> &Py<Self> {
1254        unsafe { num.obj().downcast_unchecked_ref() }
1255    }
1256
1257    #[inline]
1258    fn number_downcast_exact(num: PyNumber, vm: &VirtualMachine) -> PyRef<Self> {
1259        if let Some(zelf) = num.downcast_ref_if_exact::<Self>(vm) {
1260            zelf.to_owned()
1261        } else {
1262            Self::clone_exact(Self::number_downcast(num), vm)
1263        }
1264    }
1265}
1266
1267#[pyclass]
1268pub trait Iterable: PyPayload {
1269    #[pyslot]
1270    fn slot_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1271        let zelf = zelf
1272            .downcast()
1273            .map_err(|_| vm.new_type_error("unexpected payload for __iter__".to_owned()))?;
1274        Self::iter(zelf, vm)
1275    }
1276
1277    #[pymethod]
1278    fn __iter__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1279        Self::slot_iter(zelf, vm)
1280    }
1281
1282    fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult;
1283
1284    fn extend_slots(_slots: &mut PyTypeSlots) {}
1285}
1286
1287// `Iterator` fits better, but to avoid confusion with rust std::iter::Iterator
1288#[pyclass(with(Iterable))]
1289pub trait IterNext: PyPayload + Iterable {
1290    #[pyslot]
1291    fn slot_iternext(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
1292        let zelf = zelf
1293            .downcast_ref()
1294            .ok_or_else(|| vm.new_type_error("unexpected payload for __next__".to_owned()))?;
1295        Self::next(zelf, vm)
1296    }
1297
1298    fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn>;
1299
1300    #[inline]
1301    #[pymethod]
1302    fn __next__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1303        Self::slot_iternext(&zelf, vm).to_pyresult(vm)
1304    }
1305}
1306
1307pub trait SelfIter: PyPayload {}
1308
1309impl<T> Iterable for T
1310where
1311    T: SelfIter,
1312{
1313    #[cold]
1314    fn slot_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1315        let repr = zelf.repr(vm)?;
1316        unreachable!("slot must be overridden for {}", repr.as_str());
1317    }
1318
1319    fn __iter__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1320        self_iter(zelf, vm)
1321    }
1322
1323    #[cold]
1324    fn iter(_zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult {
1325        unreachable!("slot_iter is implemented");
1326    }
1327
1328    fn extend_slots(slots: &mut PyTypeSlots) {
1329        let prev = slots.iter.swap(Some(self_iter));
1330        debug_assert!(prev.is_some()); // slot_iter would be set
1331    }
1332}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.