1use crate::common::lock::{
2 PyMappedRwLockReadGuard, PyMappedRwLockWriteGuard, PyRwLockReadGuard, PyRwLockWriteGuard,
3};
4use crate::{
5 AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
6 builtins::{PyInt, PyStr, PyStrInterned, PyType, PyTypeRef},
7 bytecode::ComparisonOperator,
8 common::hash::{PyHash, fix_sentinel, hash_bigint},
9 convert::ToPyObject,
10 function::{Either, FromArgs, FuncArgs, PyComparisonValue, PyMethodDef, PySetterValue},
11 protocol::{
12 PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyMappingSlots, PyNumber,
13 PyNumberMethods, PyNumberSlots, PySequence, PySequenceMethods, PySequenceSlots,
14 },
15 types::slot_defs::{SlotAccessor, find_slot_defs_by_name},
16 vm::Context,
17};
18use core::{any::Any, any::TypeId, borrow::Borrow, cmp::Ordering, ops::Deref};
19use crossbeam_utils::atomic::AtomicCell;
20use num_traits::{Signed, ToPrimitive};
21use rustpython_common::wtf8::Wtf8Buf;
22
23pub struct TypeDataSlot {
25 type_id: TypeId,
27 data: Box<dyn Any + Send + Sync>,
28}
29
30impl TypeDataSlot {
31 pub fn new<T: Any + Send + Sync + 'static>(data: T) -> Self {
33 Self {
34 type_id: TypeId::of::<T>(),
35 data: Box::new(data),
36 }
37 }
38
39 pub fn get<T: Any + 'static>(&self) -> Option<&T> {
41 if self.type_id == TypeId::of::<T>() {
42 self.data.downcast_ref()
43 } else {
44 None
45 }
46 }
47
48 pub fn get_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
50 if self.type_id == TypeId::of::<T>() {
51 self.data.downcast_mut()
52 } else {
53 None
54 }
55 }
56}
57
58pub struct TypeDataRef<'a, T: 'static> {
60 guard: PyMappedRwLockReadGuard<'a, T>,
61}
62
63impl<'a, T: Any + 'static> TypeDataRef<'a, T> {
64 pub fn try_new(guard: PyRwLockReadGuard<'a, Option<TypeDataSlot>>) -> Option<Self> {
67 PyRwLockReadGuard::try_map(guard, |opt| opt.as_ref().and_then(|slot| slot.get::<T>()))
68 .ok()
69 .map(|guard| Self { guard })
70 }
71}
72
73impl<T: Any + 'static> core::ops::Deref for TypeDataRef<'_, T> {
74 type Target = T;
75
76 fn deref(&self) -> &Self::Target {
77 &self.guard
78 }
79}
80
81pub struct TypeDataRefMut<'a, T: 'static> {
83 guard: PyMappedRwLockWriteGuard<'a, T>,
84}
85
86impl<'a, T: Any + 'static> TypeDataRefMut<'a, T> {
87 pub fn try_new(guard: PyRwLockWriteGuard<'a, Option<TypeDataSlot>>) -> Option<Self> {
90 PyRwLockWriteGuard::try_map(guard, |opt| {
91 opt.as_mut().and_then(|slot| slot.get_mut::<T>())
92 })
93 .ok()
94 .map(|guard| Self { guard })
95 }
96}
97
98impl<T: Any + 'static> core::ops::Deref for TypeDataRefMut<'_, T> {
99 type Target = T;
100
101 fn deref(&self) -> &Self::Target {
102 &self.guard
103 }
104}
105
106impl<T: Any + 'static> core::ops::DerefMut for TypeDataRefMut<'_, T> {
107 fn deref_mut(&mut self) -> &mut Self::Target {
108 &mut self.guard
109 }
110}
111
112#[macro_export]
113macro_rules! atomic_func {
114 ($x:expr) => {
115 Some($x)
116 };
117}
118
119#[derive(Default)]
122#[non_exhaustive]
123pub struct PyTypeSlots {
124 pub(crate) name: &'static str, pub basicsize: usize,
130 pub itemsize: usize, pub as_number: PyNumberSlots,
136 pub as_sequence: PySequenceSlots,
137 pub as_mapping: PyMappingSlots,
138
139 pub hash: AtomicCell<Option<HashFunc>>,
141 pub call: AtomicCell<Option<GenericMethod>>,
142 pub vectorcall: AtomicCell<Option<VectorCallFunc>>,
143 pub str: AtomicCell<Option<StringifyFunc>>,
144 pub repr: AtomicCell<Option<StringifyFunc>>,
145 pub getattro: AtomicCell<Option<GetattroFunc>>,
146 pub setattro: AtomicCell<Option<SetattroFunc>>,
147
148 pub as_buffer: Option<AsBufferFunc>,
150
151 pub richcompare: AtomicCell<Option<RichCompareFunc>>,
154
155 pub iter: AtomicCell<Option<IterFunc>>,
157 pub iternext: AtomicCell<Option<IterNextFunc>>,
158
159 pub methods: &'static [PyMethodDef],
160
161 pub flags: PyTypeFlags,
163
164 pub doc: Option<&'static str>,
166
167 pub descr_get: AtomicCell<Option<DescrGetFunc>>,
171 pub descr_set: AtomicCell<Option<DescrSetFunc>>,
172 pub init: AtomicCell<Option<InitFunc>>,
174 pub alloc: AtomicCell<Option<AllocFunc>>,
176 pub new: AtomicCell<Option<NewFunc>>,
177 pub del: AtomicCell<Option<DelFunc>>,
185
186 pub member_count: usize,
188}
189
190impl PyTypeSlots {
191 pub fn new(name: &'static str, flags: PyTypeFlags) -> Self {
192 Self {
193 name,
194 flags,
195 ..Default::default()
196 }
197 }
198
199 pub fn heap_default() -> Self {
200 Self {
201 ..Default::default()
203 }
204 }
205}
206
207impl core::fmt::Debug for PyTypeSlots {
208 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
209 f.write_str("PyTypeSlots")
210 }
211}
212
213bitflags! {
214 #[derive(Copy, Clone, Debug, PartialEq)]
215 #[non_exhaustive]
216 pub struct PyTypeFlags: u64 {
217 const MANAGED_WEAKREF = 1 << 3;
218 const MANAGED_DICT = 1 << 4;
219 const SEQUENCE = 1 << 5;
220 const MAPPING = 1 << 6;
221 const DISALLOW_INSTANTIATION = 1 << 7;
222 const IMMUTABLETYPE = 1 << 8;
223 const HEAPTYPE = 1 << 9;
224 const BASETYPE = 1 << 10;
225 const METHOD_DESCRIPTOR = 1 << 17;
226 const _MATCH_SELF = 1 << 22;
230 const HAS_DICT = 1 << 40;
231 const HAS_WEAKREF = 1 << 41;
232
233 #[cfg(debug_assertions)]
234 const _CREATED_WITH_FLAGS = 1 << 63;
235 }
236}
237
238impl PyTypeFlags {
239 pub const DEFAULT: Self = Self::empty();
242
243 pub const fn heap_type_flags() -> Self {
247 match Self::from_bits(Self::DEFAULT.bits() | Self::HEAPTYPE.bits() | Self::BASETYPE.bits())
248 {
249 Some(flags) => flags,
250 None => unreachable!(),
251 }
252 }
253
254 pub const fn has_feature(self, flag: Self) -> bool {
255 self.contains(flag)
256 }
257
258 #[cfg(debug_assertions)]
259 pub const fn is_created_with_flags(self) -> bool {
260 self.contains(Self::_CREATED_WITH_FLAGS)
261 }
262}
263
264impl Default for PyTypeFlags {
265 fn default() -> Self {
266 Self::DEFAULT
267 }
268}
269
270pub(crate) type GenericMethod = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyResult;
271pub(crate) type VectorCallFunc = fn(
276 &PyObject, Vec<PyObjectRef>, usize, Option<&[PyObjectRef]>, &VirtualMachine,
281) -> PyResult;
282pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyHash>;
283pub(crate) type StringifyFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyRef<PyStr>>;
285pub(crate) type GetattroFunc = fn(&PyObject, &Py<PyStr>, &VirtualMachine) -> PyResult;
286pub(crate) type SetattroFunc =
287 fn(&PyObject, &Py<PyStr>, PySetterValue, &VirtualMachine) -> PyResult<()>;
288pub(crate) type AsBufferFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyBuffer>;
289pub(crate) type RichCompareFunc = fn(
290 &PyObject,
291 &PyObject,
292 PyComparisonOp,
293 &VirtualMachine,
294) -> PyResult<Either<PyObjectRef, PyComparisonValue>>;
295pub(crate) type IterFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult;
296pub(crate) type IterNextFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyIterReturn>;
297pub(crate) type DescrGetFunc =
298 fn(PyObjectRef, Option<PyObjectRef>, Option<PyObjectRef>, &VirtualMachine) -> PyResult;
299pub(crate) type DescrSetFunc =
300 fn(&PyObject, PyObjectRef, PySetterValue, &VirtualMachine) -> PyResult<()>;
301pub(crate) type AllocFunc = fn(PyTypeRef, usize, &VirtualMachine) -> PyResult;
302pub(crate) type NewFunc = fn(PyTypeRef, FuncArgs, &VirtualMachine) -> PyResult;
303pub(crate) type InitFunc = fn(PyObjectRef, FuncArgs, &VirtualMachine) -> PyResult<()>;
304pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>;
305
306pub(crate) type SeqLenFunc = fn(PySequence<'_>, &VirtualMachine) -> PyResult<usize>;
308pub(crate) type SeqConcatFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult;
309pub(crate) type SeqRepeatFunc = fn(PySequence<'_>, isize, &VirtualMachine) -> PyResult;
310pub(crate) type SeqItemFunc = fn(PySequence<'_>, isize, &VirtualMachine) -> PyResult;
311pub(crate) type SeqAssItemFunc =
312 fn(PySequence<'_>, isize, Option<PyObjectRef>, &VirtualMachine) -> PyResult<()>;
313pub(crate) type SeqContainsFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult<bool>;
314
315pub(crate) type MapLenFunc = fn(PyMapping<'_>, &VirtualMachine) -> PyResult<usize>;
317pub(crate) type MapSubscriptFunc = fn(PyMapping<'_>, &PyObject, &VirtualMachine) -> PyResult;
318pub(crate) type MapAssSubscriptFunc =
319 fn(PyMapping<'_>, &PyObject, Option<PyObjectRef>, &VirtualMachine) -> PyResult<()>;
320
321pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult<usize> {
323 let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?;
324 let len = ret.downcast_ref::<PyInt>().ok_or_else(|| {
325 vm.new_type_error(format!(
326 "'{}' object cannot be interpreted as an integer",
327 ret.class()
328 ))
329 })?;
330 let len = len.as_bigint();
331 if len.is_negative() {
332 return Err(vm.new_value_error("__len__() should return >= 0"));
333 }
334 let len = len
335 .to_isize()
336 .ok_or_else(|| vm.new_overflow_error("cannot fit 'int' into an index-sized integer"))?;
337 Ok(len as usize)
338}
339
340pub(crate) fn contains_wrapper(
341 obj: &PyObject,
342 needle: &PyObject,
343 vm: &VirtualMachine,
344) -> PyResult<bool> {
345 let ret = vm.call_special_method(obj, identifier!(vm, __contains__), (needle,))?;
346 ret.try_to_bool(vm)
347}
348
349macro_rules! number_unary_op_wrapper {
350 ($name:ident) => {
351 |a, vm| vm.call_special_method(a.deref(), identifier!(vm, $name), ())
352 };
353}
354macro_rules! number_binary_op_wrapper {
355 ($name:ident) => {
356 |a, b, vm| vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(),))
357 };
358}
359macro_rules! number_binary_right_op_wrapper {
360 ($name:ident) => {
361 |a, b, vm| vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),))
362 };
363}
364macro_rules! number_ternary_op_wrapper {
365 ($name:ident) => {
366 |a, b, c, vm: &VirtualMachine| {
367 if vm.is_none(c) {
368 vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(),))
369 } else {
370 vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(), c.to_owned()))
371 }
372 }
373 };
374}
375macro_rules! number_ternary_right_op_wrapper {
376 ($name:ident) => {
377 |a, b, c, vm: &VirtualMachine| {
378 if vm.is_none(c) {
379 vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),))
380 } else {
381 vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(), c.to_owned()))
382 }
383 }
384 };
385}
386fn getitem_wrapper<K: ToPyObject>(obj: &PyObject, needle: K, vm: &VirtualMachine) -> PyResult {
387 vm.call_special_method(obj, identifier!(vm, __getitem__), (needle,))
388}
389
390fn setitem_wrapper<K: ToPyObject>(
391 obj: &PyObject,
392 needle: K,
393 value: Option<PyObjectRef>,
394 vm: &VirtualMachine,
395) -> PyResult<()> {
396 match value {
397 Some(value) => vm.call_special_method(obj, identifier!(vm, __setitem__), (needle, value)),
398 None => vm.call_special_method(obj, identifier!(vm, __delitem__), (needle,)),
399 }
400 .map(drop)
401}
402
403#[inline(never)]
404fn mapping_setitem_wrapper(
405 mapping: PyMapping<'_>,
406 key: &PyObject,
407 value: Option<PyObjectRef>,
408 vm: &VirtualMachine,
409) -> PyResult<()> {
410 setitem_wrapper(mapping.obj, key, value, vm)
411}
412
413#[inline(never)]
414fn mapping_getitem_wrapper(
415 mapping: PyMapping<'_>,
416 key: &PyObject,
417 vm: &VirtualMachine,
418) -> PyResult {
419 getitem_wrapper(mapping.obj, key, vm)
420}
421
422#[inline(never)]
423fn mapping_len_wrapper(mapping: PyMapping<'_>, vm: &VirtualMachine) -> PyResult<usize> {
424 len_wrapper(mapping.obj, vm)
425}
426
427#[inline(never)]
428fn sequence_len_wrapper(seq: PySequence<'_>, vm: &VirtualMachine) -> PyResult<usize> {
429 len_wrapper(seq.obj, vm)
430}
431
432#[inline(never)]
433fn sequence_getitem_wrapper(seq: PySequence<'_>, i: isize, vm: &VirtualMachine) -> PyResult {
434 getitem_wrapper(seq.obj, i, vm)
435}
436
437#[inline(never)]
438fn sequence_setitem_wrapper(
439 seq: PySequence<'_>,
440 i: isize,
441 value: Option<PyObjectRef>,
442 vm: &VirtualMachine,
443) -> PyResult<()> {
444 setitem_wrapper(seq.obj, i, value, vm)
445}
446
447#[inline(never)]
448fn sequence_contains_wrapper(
449 seq: PySequence<'_>,
450 needle: &PyObject,
451 vm: &VirtualMachine,
452) -> PyResult<bool> {
453 contains_wrapper(seq.obj, needle, vm)
454}
455
456#[inline(never)]
457fn sequence_repeat_wrapper(seq: PySequence<'_>, n: isize, vm: &VirtualMachine) -> PyResult {
458 vm.call_special_method(seq.obj, identifier!(vm, __mul__), (n,))
459}
460
461#[inline(never)]
462fn sequence_inplace_repeat_wrapper(seq: PySequence<'_>, n: isize, vm: &VirtualMachine) -> PyResult {
463 vm.call_special_method(seq.obj, identifier!(vm, __imul__), (n,))
464}
465
466fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
467 let ret = vm.call_special_method(zelf, identifier!(vm, __repr__), ())?;
468 ret.downcast::<PyStr>().map_err(|obj| {
469 vm.new_type_error(format!(
470 "__repr__ returned non-string (type {})",
471 obj.class()
472 ))
473 })
474}
475
476fn str_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
477 let ret = vm.call_special_method(zelf, identifier!(vm, __str__), ())?;
478 ret.downcast::<PyStr>().map_err(|obj| {
479 vm.new_type_error(format!(
480 "__str__ returned non-string (type {})",
481 obj.class()
482 ))
483 })
484}
485
486fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
487 let hash_obj = vm.call_special_method(zelf, identifier!(vm, __hash__), ())?;
488 let py_int = hash_obj
489 .downcast_ref::<PyInt>()
490 .ok_or_else(|| vm.new_type_error("__hash__ method should return an integer"))?;
491 let big_int = py_int.as_bigint();
492 let hash = big_int
493 .to_i64()
494 .map(fix_sentinel)
495 .unwrap_or_else(|| hash_bigint(big_int));
496 Ok(hash)
497}
498
499pub fn hash_not_implemented(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
501 Err(vm.new_type_error(format!("unhashable type: '{}'", zelf.class().name())))
502}
503
504fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
505 vm.call_special_method(zelf, identifier!(vm, __call__), args)
506}
507
508fn getattro_wrapper(zelf: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
509 let __getattribute__ = identifier!(vm, __getattribute__);
510 let __getattr__ = identifier!(vm, __getattr__);
511 match vm.call_special_method(zelf, __getattribute__, (name.to_owned(),)) {
512 Ok(r) => Ok(r),
513 Err(e)
514 if e.fast_isinstance(vm.ctx.exceptions.attribute_error)
515 && zelf.class().has_attr(__getattr__) =>
516 {
517 vm.call_special_method(zelf, __getattr__, (name.to_owned(),))
518 }
519 Err(e) => Err(e),
520 }
521}
522
523fn setattro_wrapper(
524 zelf: &PyObject,
525 name: &Py<PyStr>,
526 value: PySetterValue,
527 vm: &VirtualMachine,
528) -> PyResult<()> {
529 let name = name.to_owned();
530 match value {
531 PySetterValue::Assign(value) => {
532 vm.call_special_method(zelf, identifier!(vm, __setattr__), (name, value))?;
533 }
534 PySetterValue::Delete => {
535 vm.call_special_method(zelf, identifier!(vm, __delattr__), (name,))?;
536 }
537 };
538 Ok(())
539}
540
541pub(crate) fn richcompare_wrapper(
542 zelf: &PyObject,
543 other: &PyObject,
544 op: PyComparisonOp,
545 vm: &VirtualMachine,
546) -> PyResult<Either<PyObjectRef, PyComparisonValue>> {
547 vm.call_special_method(zelf, op.method_name(&vm.ctx), (other.to_owned(),))
548 .map(Either::A)
549}
550
551fn iter_wrapper(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
552 let cls = zelf.class();
554 let iter_attr = cls.get_attr(identifier!(vm, __iter__));
555 match iter_attr {
556 Some(attr) if vm.is_none(&attr) => {
557 Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name())))
558 }
559 _ => vm.call_special_method(&zelf, identifier!(vm, __iter__), ()),
560 }
561}
562
563fn bool_wrapper(num: PyNumber<'_>, vm: &VirtualMachine) -> PyResult<bool> {
564 let result = vm.call_special_method(num.obj, identifier!(vm, __bool__), ())?;
565 if !result.class().is(vm.ctx.types.bool_type) {
567 return Err(vm.new_type_error(format!(
568 "__bool__ should return bool, returned {}",
569 result.class().name()
570 )));
571 }
572 Ok(crate::builtins::bool_::get_value(&result))
573}
574
575const fn self_iter(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult {
577 Ok(zelf)
578}
579
580fn iternext_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
581 PyIterReturn::from_pyresult(
582 vm.call_special_method(zelf, identifier!(vm, __next__), ()),
583 vm,
584 )
585}
586
587fn descr_get_wrapper(
588 zelf: PyObjectRef,
589 obj: Option<PyObjectRef>,
590 cls: Option<PyObjectRef>,
591 vm: &VirtualMachine,
592) -> PyResult {
593 vm.call_special_method(&zelf, identifier!(vm, __get__), (obj, cls))
594}
595
596fn descr_set_wrapper(
597 zelf: &PyObject,
598 obj: PyObjectRef,
599 value: PySetterValue,
600 vm: &VirtualMachine,
601) -> PyResult<()> {
602 match value {
603 PySetterValue::Assign(val) => {
604 vm.call_special_method(zelf, identifier!(vm, __set__), (obj, val))
605 }
606 PySetterValue::Delete => vm.call_special_method(zelf, identifier!(vm, __delete__), (obj,)),
607 }
608 .map(drop)
609}
610
611fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
612 let res = vm.call_special_method(&obj, identifier!(vm, __init__), args)?;
613 if !vm.is_none(&res) {
614 return Err(vm.new_type_error(format!(
615 "__init__() should return None, not '{:.200}'",
616 res.class().name()
617 )));
618 }
619 Ok(())
620}
621
622pub(crate) fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
623 let new = cls.get_attr(identifier!(vm, __new__)).unwrap();
624 args.prepend_arg(cls.into());
625 new.call(args, vm)
626}
627
628fn del_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
629 vm.call_special_method(zelf, identifier!(vm, __del__), ())?;
630 Ok(())
631}
632
633enum SlotLookupResult<T> {
635 NativeSlot(T),
637 PythonMethod,
640 NotFound,
643}
644
645impl PyType {
646 pub(crate) fn update_slot<const ADD: bool>(&self, name: &'static PyStrInterned, ctx: &Context) {
651 debug_assert!(name.as_str().starts_with("__"));
652 debug_assert!(name.as_str().ends_with("__"));
653
654 let defs: Vec<_> = find_slot_defs_by_name(name.as_str()).collect();
657 for def in defs {
658 self.update_one_slot::<ADD>(&def.accessor, name, ctx);
659 }
660
661 self.update_subclasses::<ADD>(name, ctx);
663 }
664
665 fn update_subclasses<const ADD: bool>(&self, name: &'static PyStrInterned, ctx: &Context) {
668 let subclasses = self.subclasses.read();
669 for weak_ref in subclasses.iter() {
670 let Some(subclass) = weak_ref.upgrade() else {
671 continue;
672 };
673 let Some(subclass) = subclass.downcast_ref::<PyType>() else {
674 continue;
675 };
676
677 if subclass.attributes.read().contains_key(name) {
679 continue;
680 }
681
682 for def in find_slot_defs_by_name(name.as_str()) {
684 subclass.update_one_slot::<ADD>(&def.accessor, name, ctx);
685 }
686
687 subclass.update_subclasses::<ADD>(name, ctx);
689 }
690 }
691
692 fn update_one_slot<const ADD: bool>(
694 &self,
695 accessor: &SlotAccessor,
696 name: &'static PyStrInterned,
697 ctx: &Context,
698 ) {
699 use crate::builtins::descriptor::SlotFunc;
700
701 macro_rules! update_main_slot {
703 ($slot:ident, $wrapper:expr, $variant:ident) => {{
704 if ADD {
705 match self.lookup_slot_in_mro(name, ctx, |sf| {
706 if let SlotFunc::$variant(f) = sf {
707 Some(*f)
708 } else {
709 None
710 }
711 }) {
712 SlotLookupResult::NativeSlot(func) => {
713 self.slots.$slot.store(Some(func));
714 }
715 SlotLookupResult::PythonMethod => {
716 self.slots.$slot.store(Some($wrapper));
717 }
718 SlotLookupResult::NotFound => {
719 accessor.inherit_from_mro(self);
720 }
721 }
722 } else {
723 accessor.inherit_from_mro(self);
724 }
725 }};
726 }
727
728 macro_rules! update_sub_slot {
730 ($group:ident, $slot:ident, $wrapper:expr, $variant:ident) => {{
731 if ADD {
732 let has_own = {
737 let guard = self.attributes.read();
738 let mut result = guard.contains_key(name);
740 if !result
743 && (stringify!($slot) == "ass_item"
744 || stringify!($slot) == "ass_subscript")
745 {
746 let setitem = ctx.intern_str("__setitem__");
747 let delitem = ctx.intern_str("__delitem__");
748 result = guard.contains_key(setitem) || guard.contains_key(delitem);
749 }
750 result
751 };
752 if has_own {
753 self.slots.$group.$slot.store(Some($wrapper));
754 } else {
755 match self.lookup_slot_in_mro(name, ctx, |sf| {
756 if let SlotFunc::$variant(f) = sf {
757 Some(*f)
758 } else {
759 None
760 }
761 }) {
762 SlotLookupResult::NativeSlot(func) => {
763 self.slots.$group.$slot.store(Some(func));
764 }
765 SlotLookupResult::PythonMethod => {
766 self.slots.$group.$slot.store(Some($wrapper));
767 }
768 SlotLookupResult::NotFound => {
769 accessor.inherit_from_mro(self);
770 }
771 }
772 }
773 } else {
774 accessor.inherit_from_mro(self);
775 }
776 }};
777 }
778
779 match accessor {
780 SlotAccessor::TpRepr => update_main_slot!(repr, repr_wrapper, Repr),
782 SlotAccessor::TpStr => update_main_slot!(str, str_wrapper, Str),
783 SlotAccessor::TpHash => {
784 if ADD {
786 let method = self.attributes.read().get(name).cloned().or_else(|| {
787 self.mro
788 .read()
789 .iter()
790 .find_map(|cls| cls.attributes.read().get(name).cloned())
791 });
792
793 if method.as_ref().is_some_and(|m| m.is(&ctx.none)) {
794 self.slots.hash.store(Some(hash_not_implemented));
795 } else {
796 match self.lookup_slot_in_mro(name, ctx, |sf| {
797 if let SlotFunc::Hash(f) = sf {
798 Some(*f)
799 } else {
800 None
801 }
802 }) {
803 SlotLookupResult::NativeSlot(func) => {
804 self.slots.hash.store(Some(func));
805 }
806 SlotLookupResult::PythonMethod => {
807 self.slots.hash.store(Some(hash_wrapper));
808 }
809 SlotLookupResult::NotFound => {
810 accessor.inherit_from_mro(self);
811 }
812 }
813 }
814 } else {
815 accessor.inherit_from_mro(self);
816 }
817 }
818 SlotAccessor::TpCall => {
819 update_main_slot!(call, call_wrapper, Call);
820 if ADD {
823 self.slots.vectorcall.store(None);
824 }
825 }
826 SlotAccessor::TpIter => update_main_slot!(iter, iter_wrapper, Iter),
827 SlotAccessor::TpIternext => update_main_slot!(iternext, iternext_wrapper, IterNext),
828 SlotAccessor::TpInit => {
829 update_main_slot!(init, init_wrapper, Init);
830 if ADD {
831 self.slots.vectorcall.store(None);
832 }
833 }
834 SlotAccessor::TpNew => {
835 if ADD {
837 self.slots.new.store(Some(new_wrapper));
838 self.slots.vectorcall.store(None);
839 } else {
840 accessor.inherit_from_mro(self);
841 }
842 }
843 SlotAccessor::TpDel => update_main_slot!(del, del_wrapper, Del),
844 SlotAccessor::TpGetattro => {
845 let __getattr__ = identifier!(ctx, __getattr__);
849 let has_getattr = {
850 let attrs = self.attributes.read();
851 let in_self = attrs.contains_key(__getattr__);
852 drop(attrs);
853 in_self
855 || self
856 .mro
857 .read()
858 .iter()
859 .skip(1)
860 .any(|cls| cls.attributes.read().contains_key(__getattr__))
861 };
862
863 if has_getattr {
864 self.slots.getattro.store(Some(getattro_wrapper));
866 } else if ADD {
867 match self.lookup_slot_in_mro(name, ctx, |sf| {
868 if let SlotFunc::GetAttro(f) = sf {
869 Some(*f)
870 } else {
871 None
872 }
873 }) {
874 SlotLookupResult::NativeSlot(func) => {
875 self.slots.getattro.store(Some(func));
876 }
877 SlotLookupResult::PythonMethod => {
878 self.slots.getattro.store(Some(getattro_wrapper));
879 }
880 SlotLookupResult::NotFound => {
881 accessor.inherit_from_mro(self);
882 }
883 }
884 } else {
885 accessor.inherit_from_mro(self);
886 }
887 }
888 SlotAccessor::TpSetattro => {
889 if ADD {
891 match self.lookup_slot_in_mro(name, ctx, |sf| match sf {
892 SlotFunc::SetAttro(f) | SlotFunc::DelAttro(f) => Some(*f),
893 _ => None,
894 }) {
895 SlotLookupResult::NativeSlot(func) => {
896 self.slots.setattro.store(Some(func));
897 }
898 SlotLookupResult::PythonMethod => {
899 self.slots.setattro.store(Some(setattro_wrapper));
900 }
901 SlotLookupResult::NotFound => {
902 accessor.inherit_from_mro(self);
903 }
904 }
905 } else {
906 accessor.inherit_from_mro(self);
907 }
908 }
909 SlotAccessor::TpDescrGet => update_main_slot!(descr_get, descr_get_wrapper, DescrGet),
910 SlotAccessor::TpDescrSet => {
911 if ADD {
913 match self.lookup_slot_in_mro(name, ctx, |sf| match sf {
914 SlotFunc::DescrSet(f) | SlotFunc::DescrDel(f) => Some(*f),
915 _ => None,
916 }) {
917 SlotLookupResult::NativeSlot(func) => {
918 self.slots.descr_set.store(Some(func));
919 }
920 SlotLookupResult::PythonMethod => {
921 self.slots.descr_set.store(Some(descr_set_wrapper));
922 }
923 SlotLookupResult::NotFound => {
924 accessor.inherit_from_mro(self);
925 }
926 }
927 } else {
928 accessor.inherit_from_mro(self);
929 }
930 }
931
932 SlotAccessor::TpRichcompare => {
934 if ADD {
935 let cmp_names = [
939 identifier!(ctx, __eq__),
940 identifier!(ctx, __ne__),
941 identifier!(ctx, __lt__),
942 identifier!(ctx, __le__),
943 identifier!(ctx, __gt__),
944 identifier!(ctx, __ge__),
945 ];
946
947 let has_python_cmp = {
948 let attrs = self.attributes.read();
950 let in_self = cmp_names.iter().any(|n| attrs.contains_key(*n));
951 drop(attrs);
952
953 in_self
955 || self.mro.read()[1..].iter().any(|cls| {
956 let attrs = cls.attributes.read();
957 cmp_names.iter().any(|n| {
958 if let Some(attr) = attrs.get(*n) {
959 !attr.class().is(ctx.types.wrapper_descriptor_type)
961 && !attr.class().is(ctx.types.method_descriptor_type)
962 } else {
963 false
964 }
965 })
966 })
967 };
968
969 if has_python_cmp {
970 self.slots.richcompare.store(Some(richcompare_wrapper));
972 } else {
973 match self.lookup_slot_in_mro(name, ctx, |sf| {
974 if let SlotFunc::RichCompare(f, _) = sf {
975 Some(*f)
976 } else {
977 None
978 }
979 }) {
980 SlotLookupResult::NativeSlot(func) => {
981 self.slots.richcompare.store(Some(func));
982 }
983 SlotLookupResult::PythonMethod => {
984 self.slots.richcompare.store(Some(richcompare_wrapper));
985 }
986 SlotLookupResult::NotFound => {
987 accessor.inherit_from_mro(self);
988 }
989 }
990 }
991 } else {
992 accessor.inherit_from_mro(self);
993 }
994 }
995
996 SlotAccessor::NbAdd => {
998 if name.as_str() == "__radd__" {
999 update_sub_slot!(
1000 as_number,
1001 right_add,
1002 number_binary_right_op_wrapper!(__radd__),
1003 NumBinary
1004 )
1005 } else {
1006 update_sub_slot!(
1007 as_number,
1008 add,
1009 number_binary_op_wrapper!(__add__),
1010 NumBinary
1011 )
1012 }
1013 }
1014 SlotAccessor::NbInplaceAdd => {
1015 update_sub_slot!(
1016 as_number,
1017 inplace_add,
1018 number_binary_op_wrapper!(__iadd__),
1019 NumBinary
1020 )
1021 }
1022 SlotAccessor::NbSubtract => {
1023 if name.as_str() == "__rsub__" {
1024 update_sub_slot!(
1025 as_number,
1026 right_subtract,
1027 number_binary_right_op_wrapper!(__rsub__),
1028 NumBinary
1029 )
1030 } else {
1031 update_sub_slot!(
1032 as_number,
1033 subtract,
1034 number_binary_op_wrapper!(__sub__),
1035 NumBinary
1036 )
1037 }
1038 }
1039 SlotAccessor::NbInplaceSubtract => {
1040 update_sub_slot!(
1041 as_number,
1042 inplace_subtract,
1043 number_binary_op_wrapper!(__isub__),
1044 NumBinary
1045 )
1046 }
1047 SlotAccessor::NbMultiply => {
1048 if name.as_str() == "__rmul__" {
1049 update_sub_slot!(
1050 as_number,
1051 right_multiply,
1052 number_binary_right_op_wrapper!(__rmul__),
1053 NumBinary
1054 )
1055 } else {
1056 update_sub_slot!(
1057 as_number,
1058 multiply,
1059 number_binary_op_wrapper!(__mul__),
1060 NumBinary
1061 )
1062 }
1063 }
1064 SlotAccessor::NbInplaceMultiply => {
1065 update_sub_slot!(
1066 as_number,
1067 inplace_multiply,
1068 number_binary_op_wrapper!(__imul__),
1069 NumBinary
1070 )
1071 }
1072 SlotAccessor::NbRemainder => {
1073 if name.as_str() == "__rmod__" {
1074 update_sub_slot!(
1075 as_number,
1076 right_remainder,
1077 number_binary_right_op_wrapper!(__rmod__),
1078 NumBinary
1079 )
1080 } else {
1081 update_sub_slot!(
1082 as_number,
1083 remainder,
1084 number_binary_op_wrapper!(__mod__),
1085 NumBinary
1086 )
1087 }
1088 }
1089 SlotAccessor::NbInplaceRemainder => {
1090 update_sub_slot!(
1091 as_number,
1092 inplace_remainder,
1093 number_binary_op_wrapper!(__imod__),
1094 NumBinary
1095 )
1096 }
1097 SlotAccessor::NbDivmod => {
1098 if name.as_str() == "__rdivmod__" {
1099 update_sub_slot!(
1100 as_number,
1101 right_divmod,
1102 number_binary_right_op_wrapper!(__rdivmod__),
1103 NumBinary
1104 )
1105 } else {
1106 update_sub_slot!(
1107 as_number,
1108 divmod,
1109 number_binary_op_wrapper!(__divmod__),
1110 NumBinary
1111 )
1112 }
1113 }
1114 SlotAccessor::NbPower => {
1115 if name.as_str() == "__rpow__" {
1116 update_sub_slot!(
1117 as_number,
1118 right_power,
1119 number_ternary_right_op_wrapper!(__rpow__),
1120 NumTernary
1121 )
1122 } else {
1123 update_sub_slot!(
1124 as_number,
1125 power,
1126 number_ternary_op_wrapper!(__pow__),
1127 NumTernary
1128 )
1129 }
1130 }
1131 SlotAccessor::NbInplacePower => {
1132 update_sub_slot!(
1133 as_number,
1134 inplace_power,
1135 number_ternary_op_wrapper!(__ipow__),
1136 NumTernary
1137 )
1138 }
1139 SlotAccessor::NbFloorDivide => {
1140 if name.as_str() == "__rfloordiv__" {
1141 update_sub_slot!(
1142 as_number,
1143 right_floor_divide,
1144 number_binary_right_op_wrapper!(__rfloordiv__),
1145 NumBinary
1146 )
1147 } else {
1148 update_sub_slot!(
1149 as_number,
1150 floor_divide,
1151 number_binary_op_wrapper!(__floordiv__),
1152 NumBinary
1153 )
1154 }
1155 }
1156 SlotAccessor::NbInplaceFloorDivide => {
1157 update_sub_slot!(
1158 as_number,
1159 inplace_floor_divide,
1160 number_binary_op_wrapper!(__ifloordiv__),
1161 NumBinary
1162 )
1163 }
1164 SlotAccessor::NbTrueDivide => {
1165 if name.as_str() == "__rtruediv__" {
1166 update_sub_slot!(
1167 as_number,
1168 right_true_divide,
1169 number_binary_right_op_wrapper!(__rtruediv__),
1170 NumBinary
1171 )
1172 } else {
1173 update_sub_slot!(
1174 as_number,
1175 true_divide,
1176 number_binary_op_wrapper!(__truediv__),
1177 NumBinary
1178 )
1179 }
1180 }
1181 SlotAccessor::NbInplaceTrueDivide => {
1182 update_sub_slot!(
1183 as_number,
1184 inplace_true_divide,
1185 number_binary_op_wrapper!(__itruediv__),
1186 NumBinary
1187 )
1188 }
1189 SlotAccessor::NbMatrixMultiply => {
1190 if name.as_str() == "__rmatmul__" {
1191 update_sub_slot!(
1192 as_number,
1193 right_matrix_multiply,
1194 number_binary_right_op_wrapper!(__rmatmul__),
1195 NumBinary
1196 )
1197 } else {
1198 update_sub_slot!(
1199 as_number,
1200 matrix_multiply,
1201 number_binary_op_wrapper!(__matmul__),
1202 NumBinary
1203 )
1204 }
1205 }
1206 SlotAccessor::NbInplaceMatrixMultiply => {
1207 update_sub_slot!(
1208 as_number,
1209 inplace_matrix_multiply,
1210 number_binary_op_wrapper!(__imatmul__),
1211 NumBinary
1212 )
1213 }
1214
1215 SlotAccessor::NbLshift => {
1217 if name.as_str() == "__rlshift__" {
1218 update_sub_slot!(
1219 as_number,
1220 right_lshift,
1221 number_binary_right_op_wrapper!(__rlshift__),
1222 NumBinary
1223 )
1224 } else {
1225 update_sub_slot!(
1226 as_number,
1227 lshift,
1228 number_binary_op_wrapper!(__lshift__),
1229 NumBinary
1230 )
1231 }
1232 }
1233 SlotAccessor::NbInplaceLshift => {
1234 update_sub_slot!(
1235 as_number,
1236 inplace_lshift,
1237 number_binary_op_wrapper!(__ilshift__),
1238 NumBinary
1239 )
1240 }
1241 SlotAccessor::NbRshift => {
1242 if name.as_str() == "__rrshift__" {
1243 update_sub_slot!(
1244 as_number,
1245 right_rshift,
1246 number_binary_right_op_wrapper!(__rrshift__),
1247 NumBinary
1248 )
1249 } else {
1250 update_sub_slot!(
1251 as_number,
1252 rshift,
1253 number_binary_op_wrapper!(__rshift__),
1254 NumBinary
1255 )
1256 }
1257 }
1258 SlotAccessor::NbInplaceRshift => {
1259 update_sub_slot!(
1260 as_number,
1261 inplace_rshift,
1262 number_binary_op_wrapper!(__irshift__),
1263 NumBinary
1264 )
1265 }
1266 SlotAccessor::NbAnd => {
1267 if name.as_str() == "__rand__" {
1268 update_sub_slot!(
1269 as_number,
1270 right_and,
1271 number_binary_right_op_wrapper!(__rand__),
1272 NumBinary
1273 )
1274 } else {
1275 update_sub_slot!(
1276 as_number,
1277 and,
1278 number_binary_op_wrapper!(__and__),
1279 NumBinary
1280 )
1281 }
1282 }
1283 SlotAccessor::NbInplaceAnd => {
1284 update_sub_slot!(
1285 as_number,
1286 inplace_and,
1287 number_binary_op_wrapper!(__iand__),
1288 NumBinary
1289 )
1290 }
1291 SlotAccessor::NbXor => {
1292 if name.as_str() == "__rxor__" {
1293 update_sub_slot!(
1294 as_number,
1295 right_xor,
1296 number_binary_right_op_wrapper!(__rxor__),
1297 NumBinary
1298 )
1299 } else {
1300 update_sub_slot!(
1301 as_number,
1302 xor,
1303 number_binary_op_wrapper!(__xor__),
1304 NumBinary
1305 )
1306 }
1307 }
1308 SlotAccessor::NbInplaceXor => {
1309 update_sub_slot!(
1310 as_number,
1311 inplace_xor,
1312 number_binary_op_wrapper!(__ixor__),
1313 NumBinary
1314 )
1315 }
1316 SlotAccessor::NbOr => {
1317 if name.as_str() == "__ror__" {
1318 update_sub_slot!(
1319 as_number,
1320 right_or,
1321 number_binary_right_op_wrapper!(__ror__),
1322 NumBinary
1323 )
1324 } else {
1325 update_sub_slot!(as_number, or, number_binary_op_wrapper!(__or__), NumBinary)
1326 }
1327 }
1328 SlotAccessor::NbInplaceOr => {
1329 update_sub_slot!(
1330 as_number,
1331 inplace_or,
1332 number_binary_op_wrapper!(__ior__),
1333 NumBinary
1334 )
1335 }
1336
1337 SlotAccessor::NbNegative => {
1339 update_sub_slot!(
1340 as_number,
1341 negative,
1342 number_unary_op_wrapper!(__neg__),
1343 NumUnary
1344 )
1345 }
1346 SlotAccessor::NbPositive => {
1347 update_sub_slot!(
1348 as_number,
1349 positive,
1350 number_unary_op_wrapper!(__pos__),
1351 NumUnary
1352 )
1353 }
1354 SlotAccessor::NbAbsolute => {
1355 update_sub_slot!(
1356 as_number,
1357 absolute,
1358 number_unary_op_wrapper!(__abs__),
1359 NumUnary
1360 )
1361 }
1362 SlotAccessor::NbInvert => {
1363 update_sub_slot!(
1364 as_number,
1365 invert,
1366 number_unary_op_wrapper!(__invert__),
1367 NumUnary
1368 )
1369 }
1370 SlotAccessor::NbBool => {
1371 update_sub_slot!(as_number, boolean, bool_wrapper, NumBoolean)
1372 }
1373 SlotAccessor::NbInt => {
1374 update_sub_slot!(as_number, int, number_unary_op_wrapper!(__int__), NumUnary)
1375 }
1376 SlotAccessor::NbFloat => {
1377 update_sub_slot!(
1378 as_number,
1379 float,
1380 number_unary_op_wrapper!(__float__),
1381 NumUnary
1382 )
1383 }
1384 SlotAccessor::NbIndex => {
1385 update_sub_slot!(
1386 as_number,
1387 index,
1388 number_unary_op_wrapper!(__index__),
1389 NumUnary
1390 )
1391 }
1392
1393 SlotAccessor::SqLength => {
1395 update_sub_slot!(as_sequence, length, sequence_len_wrapper, SeqLength)
1396 }
1397 SlotAccessor::SqConcat | SlotAccessor::SqInplaceConcat => {
1398 if !ADD {
1401 accessor.inherit_from_mro(self);
1402 }
1403 }
1404 SlotAccessor::SqRepeat => {
1405 update_sub_slot!(as_sequence, repeat, sequence_repeat_wrapper, SeqRepeat)
1406 }
1407 SlotAccessor::SqInplaceRepeat => {
1408 update_sub_slot!(
1409 as_sequence,
1410 inplace_repeat,
1411 sequence_inplace_repeat_wrapper,
1412 SeqRepeat
1413 )
1414 }
1415 SlotAccessor::SqItem => {
1416 update_sub_slot!(as_sequence, item, sequence_getitem_wrapper, SeqItem)
1417 }
1418 SlotAccessor::SqAssItem => {
1419 if ADD {
1421 let has_own = {
1422 let guard = self.attributes.read();
1423 let setitem = ctx.intern_str("__setitem__");
1424 let delitem = ctx.intern_str("__delitem__");
1425 guard.contains_key(setitem) || guard.contains_key(delitem)
1426 };
1427 if has_own {
1428 self.slots
1429 .as_sequence
1430 .ass_item
1431 .store(Some(sequence_setitem_wrapper));
1432 } else {
1433 match self.lookup_slot_in_mro(name, ctx, |sf| match sf {
1434 SlotFunc::SeqSetItem(f) | SlotFunc::SeqDelItem(f) => Some(*f),
1435 _ => None,
1436 }) {
1437 SlotLookupResult::NativeSlot(func) => {
1438 self.slots.as_sequence.ass_item.store(Some(func));
1439 }
1440 SlotLookupResult::PythonMethod => {
1441 self.slots
1442 .as_sequence
1443 .ass_item
1444 .store(Some(sequence_setitem_wrapper));
1445 }
1446 SlotLookupResult::NotFound => {
1447 accessor.inherit_from_mro(self);
1448 }
1449 }
1450 }
1451 } else {
1452 accessor.inherit_from_mro(self);
1453 }
1454 }
1455 SlotAccessor::SqContains => {
1456 update_sub_slot!(
1457 as_sequence,
1458 contains,
1459 sequence_contains_wrapper,
1460 SeqContains
1461 )
1462 }
1463
1464 SlotAccessor::MpLength => {
1466 update_sub_slot!(as_mapping, length, mapping_len_wrapper, MapLength)
1467 }
1468 SlotAccessor::MpSubscript => {
1469 update_sub_slot!(as_mapping, subscript, mapping_getitem_wrapper, MapSubscript)
1470 }
1471 SlotAccessor::MpAssSubscript => {
1472 if ADD {
1474 let has_own = {
1475 let guard = self.attributes.read();
1476 let setitem = ctx.intern_str("__setitem__");
1477 let delitem = ctx.intern_str("__delitem__");
1478 guard.contains_key(setitem) || guard.contains_key(delitem)
1479 };
1480 if has_own {
1481 self.slots
1482 .as_mapping
1483 .ass_subscript
1484 .store(Some(mapping_setitem_wrapper));
1485 } else {
1486 match self.lookup_slot_in_mro(name, ctx, |sf| match sf {
1487 SlotFunc::MapSetSubscript(f) | SlotFunc::MapDelSubscript(f) => Some(*f),
1488 _ => None,
1489 }) {
1490 SlotLookupResult::NativeSlot(func) => {
1491 self.slots.as_mapping.ass_subscript.store(Some(func));
1492 }
1493 SlotLookupResult::PythonMethod => {
1494 self.slots
1495 .as_mapping
1496 .ass_subscript
1497 .store(Some(mapping_setitem_wrapper));
1498 }
1499 SlotLookupResult::NotFound => {
1500 accessor.inherit_from_mro(self);
1501 }
1502 }
1503 }
1504 } else {
1505 accessor.inherit_from_mro(self);
1506 }
1507 }
1508
1509 _ => {}
1511 }
1512 }
1513
1514 fn lookup_slot_in_mro<T: Copy>(
1516 &self,
1517 name: &'static PyStrInterned,
1518 ctx: &Context,
1519 extract: impl Fn(&crate::builtins::descriptor::SlotFunc) -> Option<T>,
1520 ) -> SlotLookupResult<T> {
1521 use crate::builtins::descriptor::PyWrapper;
1522
1523 let is_subclass_of = |subclass_mro: &[PyRef<PyType>], superclass: &Py<PyType>| -> bool {
1525 subclass_mro.iter().any(|c| c.is(superclass))
1526 };
1527
1528 let try_extract = |attr: &PyObjectRef, for_class_mro: &[PyRef<PyType>]| -> Option<T> {
1532 if attr.class().is(ctx.types.wrapper_descriptor_type) {
1533 attr.downcast_ref::<PyWrapper>().and_then(|wrapper| {
1534 if is_subclass_of(for_class_mro, wrapper.typ) {
1536 extract(&wrapper.wrapped)
1537 } else {
1538 None
1539 }
1540 })
1541 } else {
1542 None
1543 }
1544 };
1545
1546 let mro = self.mro.read();
1547
1548 if let Some(attr) = self.attributes.read().get(name).cloned() {
1550 if let Some(func) = try_extract(&attr, &mro) {
1551 return SlotLookupResult::NativeSlot(func);
1552 }
1553 return SlotLookupResult::PythonMethod;
1554 }
1555
1556 for (i, cls) in mro[1..].iter().enumerate() {
1558 if let Some(attr) = cls.attributes.read().get(name).cloned() {
1559 if let Some(func) = try_extract(&attr, &mro[i + 1..]) {
1561 return SlotLookupResult::NativeSlot(func);
1562 }
1563 return SlotLookupResult::PythonMethod;
1564 }
1565 }
1566 SlotLookupResult::NotFound
1568 }
1569}
1570
1571#[pyclass]
1594pub trait Constructor: PyPayload + core::fmt::Debug {
1595 type Args: FromArgs;
1596
1597 #[inline]
1600 #[pyslot]
1601 fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1602 let args: Self::Args = args.bind(vm)?;
1603 let payload = Self::py_new(&cls, args, vm)?;
1604 payload.into_ref_with_type(vm, cls).map(Into::into)
1605 }
1606
1607 fn py_new(cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self>;
1610}
1611
1612pub trait DefaultConstructor: PyPayload + Default + core::fmt::Debug {
1613 fn construct_and_init(args: Self::Args, vm: &VirtualMachine) -> PyResult<PyRef<Self>>
1614 where
1615 Self: Initializer,
1616 {
1617 let this = Self::default().into_ref(&vm.ctx);
1618 Self::init(this.clone(), args, vm)?;
1619 Ok(this)
1620 }
1621}
1622
1623impl<T> Constructor for T
1624where
1625 T: DefaultConstructor,
1626{
1627 type Args = FuncArgs;
1628
1629 fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1630 Self::default().into_ref_with_type(vm, cls).map(Into::into)
1631 }
1632
1633 fn py_new(cls: &Py<PyType>, _args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
1634 Err(vm.new_type_error(format!("cannot create {} instances", cls.slot_name())))
1635 }
1636}
1637
1638#[pyclass]
1639pub trait Initializer: PyPayload {
1640 type Args: FromArgs;
1641
1642 #[inline]
1643 #[pyslot]
1644 fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
1645 #[cfg(debug_assertions)]
1646 let class_name_for_debug = zelf.class().name().to_string();
1647
1648 let zelf = match zelf.try_into_value(vm) {
1649 Ok(zelf) => zelf,
1650 Err(err) => {
1651 #[cfg(debug_assertions)]
1652 {
1653 if let Ok(msg) = err.as_object().repr(vm) {
1654 let double_appearance = msg
1655 .to_string_lossy()
1656 .matches(&class_name_for_debug as &str)
1657 .count()
1658 == 2;
1659 if double_appearance {
1660 panic!(
1661 "This type `{}` doesn't seem to support `init`. Override `slot_init` instead: {}",
1662 class_name_for_debug, msg
1663 );
1664 }
1665 }
1666 }
1667 return Err(err);
1668 }
1669 };
1670 let args: Self::Args = args.bind(vm)?;
1671 Self::init(zelf, args, vm)
1672 }
1673
1674 fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()>;
1675}
1676
1677#[pyclass]
1678pub trait Destructor: PyPayload {
1679 #[inline] #[pyslot]
1681 fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
1682 let zelf = zelf
1683 .downcast_ref()
1684 .ok_or_else(|| vm.new_type_error("unexpected payload for __del__"))?;
1685 Self::del(zelf, vm)
1686 }
1687
1688 fn del(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<()>;
1689}
1690
1691#[pyclass]
1692pub trait Callable: PyPayload {
1693 type Args: FromArgs;
1694
1695 #[inline]
1696 #[pyslot]
1697 fn slot_call(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1698 let zelf = zelf.downcast_ref().ok_or_else(|| {
1699 let repr = zelf.repr(vm);
1700 let help: Wtf8Buf = if let Ok(repr) = repr.as_ref() {
1701 repr.as_wtf8().to_owned()
1702 } else {
1703 zelf.class().name().to_owned().into()
1704 };
1705 let mut msg = Wtf8Buf::from("unexpected payload for __call__ of ");
1706 msg.push_wtf8(&help);
1707 vm.new_type_error(msg)
1708 })?;
1709 let args = args.bind(vm)?;
1710 Self::call(zelf, args, vm)
1711 }
1712
1713 fn call(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult;
1714}
1715
1716#[pyclass]
1717pub trait GetDescriptor: PyPayload {
1718 #[pyslot]
1719 fn descr_get(
1720 zelf: PyObjectRef,
1721 obj: Option<PyObjectRef>,
1722 cls: Option<PyObjectRef>,
1723 vm: &VirtualMachine,
1724 ) -> PyResult;
1725
1726 #[inline]
1727 fn _as_pyref<'a>(zelf: &'a PyObject, vm: &VirtualMachine) -> PyResult<&'a Py<Self>> {
1728 zelf.try_to_value(vm)
1729 }
1730
1731 #[inline]
1732 fn _unwrap<'a>(
1733 zelf: &'a PyObject,
1734 obj: Option<PyObjectRef>,
1735 vm: &VirtualMachine,
1736 ) -> PyResult<(&'a Py<Self>, PyObjectRef)> {
1737 let zelf = Self::_as_pyref(zelf, vm)?;
1738 let obj = vm.unwrap_or_none(obj);
1739 Ok((zelf, obj))
1740 }
1741
1742 #[inline]
1743 fn _check<'a>(
1744 zelf: &'a PyObject,
1745 obj: Option<PyObjectRef>,
1746 vm: &VirtualMachine,
1747 ) -> Option<(&'a Py<Self>, PyObjectRef)> {
1748 let obj = obj?;
1750 Some((Self::_as_pyref(zelf, vm).unwrap(), obj))
1761 }
1762
1763 #[inline]
1764 fn _cls_is(cls: &Option<PyObjectRef>, other: &impl Borrow<PyObject>) -> bool {
1765 cls.as_ref().is_some_and(|cls| other.borrow().is(cls))
1766 }
1767}
1768
1769#[pyclass]
1770pub trait Hashable: PyPayload {
1771 #[inline]
1772 #[pyslot]
1773 fn slot_hash(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
1774 let zelf = zelf
1775 .downcast_ref()
1776 .ok_or_else(|| vm.new_type_error("unexpected payload for __hash__"))?;
1777 Self::hash(zelf, vm)
1778 }
1779
1780 fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash>;
1781}
1782
1783#[pyclass]
1784pub trait Representable: PyPayload {
1785 #[inline]
1786 #[pyslot]
1787 fn slot_repr(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
1788 let zelf = zelf
1789 .downcast_ref()
1790 .ok_or_else(|| vm.new_type_error("unexpected payload for __repr__"))?;
1791 Self::repr(zelf, vm)
1792 }
1793
1794 #[inline]
1795 fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
1796 let repr = Self::repr_wtf8(zelf, vm)?;
1797 Ok(vm.ctx.new_str(repr))
1798 }
1799
1800 fn repr_wtf8(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
1801 Self::repr_str(zelf, vm).map(|utf8| utf8.into())
1802 }
1803 fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
1804 unreachable!("Representable requires overriding either repr_str or repr_wtf8")
1805 }
1806}
1807
1808#[pyclass]
1809pub trait Comparable: PyPayload {
1810 #[inline]
1811 #[pyslot]
1812 fn slot_richcompare(
1813 zelf: &PyObject,
1814 other: &PyObject,
1815 op: PyComparisonOp,
1816 vm: &VirtualMachine,
1817 ) -> PyResult<Either<PyObjectRef, PyComparisonValue>> {
1818 let zelf = zelf.downcast_ref().ok_or_else(|| {
1819 vm.new_type_error(format!(
1820 "unexpected payload for {}",
1821 op.method_name(&vm.ctx).as_str()
1822 ))
1823 })?;
1824 Self::cmp(zelf, other, op, vm).map(Either::B)
1825 }
1826
1827 fn cmp(
1828 zelf: &Py<Self>,
1829 other: &PyObject,
1830 op: PyComparisonOp,
1831 vm: &VirtualMachine,
1832 ) -> PyResult<PyComparisonValue>;
1833}
1834
1835#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1836#[repr(transparent)]
1837pub struct PyComparisonOp(ComparisonOperator);
1838
1839impl From<ComparisonOperator> for PyComparisonOp {
1840 fn from(op: ComparisonOperator) -> Self {
1841 Self(op)
1842 }
1843}
1844
1845#[allow(non_upper_case_globals)]
1846impl PyComparisonOp {
1847 pub const Lt: Self = Self(ComparisonOperator::Less);
1848 pub const Gt: Self = Self(ComparisonOperator::Greater);
1849 pub const Ne: Self = Self(ComparisonOperator::NotEqual);
1850 pub const Eq: Self = Self(ComparisonOperator::Equal);
1851 pub const Le: Self = Self(ComparisonOperator::LessOrEqual);
1852 pub const Ge: Self = Self(ComparisonOperator::GreaterOrEqual);
1853}
1854
1855impl PyComparisonOp {
1856 pub fn eq_only(
1857 self,
1858 f: impl FnOnce() -> PyResult<PyComparisonValue>,
1859 ) -> PyResult<PyComparisonValue> {
1860 match self {
1861 Self::Eq => f(),
1862 Self::Ne => f().map(|x| x.map(|eq| !eq)),
1863 _ => Ok(PyComparisonValue::NotImplemented),
1864 }
1865 }
1866
1867 pub fn eval_ord(self, ord: Ordering) -> bool {
1868 match self {
1869 Self::Lt => ord == Ordering::Less,
1870 Self::Le => ord != Ordering::Greater,
1871 Self::Eq => ord == Ordering::Equal,
1872 Self::Ne => ord != Ordering::Equal,
1873 Self::Gt => ord == Ordering::Greater,
1874 Self::Ge => ord != Ordering::Less,
1875 }
1876 }
1877
1878 pub const fn swapped(self) -> Self {
1879 match self {
1880 Self::Lt => Self::Gt,
1881 Self::Le => Self::Ge,
1882 Self::Eq => Self::Eq,
1883 Self::Ne => Self::Ne,
1884 Self::Ge => Self::Le,
1885 Self::Gt => Self::Lt,
1886 }
1887 }
1888
1889 pub fn method_name(self, ctx: &Context) -> &'static PyStrInterned {
1890 match self {
1891 Self::Lt => identifier!(ctx, __lt__),
1892 Self::Le => identifier!(ctx, __le__),
1893 Self::Eq => identifier!(ctx, __eq__),
1894 Self::Ne => identifier!(ctx, __ne__),
1895 Self::Ge => identifier!(ctx, __ge__),
1896 Self::Gt => identifier!(ctx, __gt__),
1897 }
1898 }
1899
1900 pub const fn operator_token(self) -> &'static str {
1901 match self {
1902 Self::Lt => "<",
1903 Self::Le => "<=",
1904 Self::Eq => "==",
1905 Self::Ne => "!=",
1906 Self::Ge => ">=",
1907 Self::Gt => ">",
1908 }
1909 }
1910
1911 #[inline]
1914 pub fn identical_optimization(
1915 self,
1916 a: &impl Borrow<PyObject>,
1917 b: &impl Borrow<PyObject>,
1918 ) -> Option<bool> {
1919 self.map_eq(|| a.borrow().is(b.borrow()))
1920 }
1921
1922 #[inline]
1925 pub fn map_eq(self, f: impl FnOnce() -> bool) -> Option<bool> {
1926 let eq = match self {
1927 Self::Eq => true,
1928 Self::Ne => false,
1929 _ => return None,
1930 };
1931 f().then_some(eq)
1932 }
1933}
1934
1935#[pyclass]
1936pub trait GetAttr: PyPayload {
1937 #[pyslot]
1938 fn slot_getattro(obj: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
1939 let zelf = obj
1940 .downcast_ref()
1941 .ok_or_else(|| vm.new_type_error("unexpected payload for __getattribute__"))?;
1942 Self::getattro(zelf, name, vm)
1943 }
1944
1945 fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult;
1946}
1947
1948#[pyclass]
1949pub trait SetAttr: PyPayload {
1950 #[pyslot]
1951 #[inline]
1952 fn slot_setattro(
1953 obj: &PyObject,
1954 name: &Py<PyStr>,
1955 value: PySetterValue,
1956 vm: &VirtualMachine,
1957 ) -> PyResult<()> {
1958 let zelf = obj
1959 .downcast_ref::<Self>()
1960 .ok_or_else(|| vm.new_type_error("unexpected payload for __setattr__"))?;
1961 Self::setattro(zelf, name, value, vm)
1962 }
1963
1964 fn setattro(
1965 zelf: &Py<Self>,
1966 name: &Py<PyStr>,
1967 value: PySetterValue,
1968 vm: &VirtualMachine,
1969 ) -> PyResult<()>;
1970}
1971
1972#[pyclass]
1973pub trait AsBuffer: PyPayload {
1974 #[inline]
1976 #[pyslot]
1977 fn slot_as_buffer(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyBuffer> {
1978 let zelf = zelf
1979 .downcast_ref()
1980 .ok_or_else(|| vm.new_type_error("unexpected payload for as_buffer"))?;
1981 Self::as_buffer(zelf, vm)
1982 }
1983
1984 fn as_buffer(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyBuffer>;
1985}
1986
1987#[pyclass]
1988pub trait AsMapping: PyPayload {
1989 fn as_mapping() -> &'static PyMappingMethods;
1990
1991 #[inline]
1992 fn mapping_downcast(mapping: PyMapping<'_>) -> &Py<Self> {
1993 unsafe { mapping.obj.downcast_unchecked_ref() }
1994 }
1995
1996 fn extend_slots(slots: &mut PyTypeSlots) {
1997 slots.as_mapping.copy_from(Self::as_mapping());
1998 }
1999}
2000
2001#[pyclass]
2002pub trait AsSequence: PyPayload {
2003 fn as_sequence() -> &'static PySequenceMethods;
2004
2005 #[inline]
2006 fn sequence_downcast(seq: PySequence<'_>) -> &Py<Self> {
2007 unsafe { seq.obj.downcast_unchecked_ref() }
2008 }
2009
2010 fn extend_slots(slots: &mut PyTypeSlots) {
2011 slots.as_sequence.copy_from(Self::as_sequence());
2012 }
2013}
2014
2015#[pyclass]
2016pub trait AsNumber: PyPayload {
2017 #[pyslot]
2018 fn as_number() -> &'static PyNumberMethods;
2019
2020 fn extend_slots(slots: &mut PyTypeSlots) {
2021 slots.as_number.copy_from(Self::as_number());
2022 }
2023
2024 fn clone_exact(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
2025 unimplemented!()
2027 }
2028
2029 #[inline]
2030 fn number_downcast(num: PyNumber<'_>) -> &Py<Self> {
2031 unsafe { num.obj.downcast_unchecked_ref() }
2032 }
2033
2034 #[inline]
2035 fn number_downcast_exact(num: PyNumber<'_>, vm: &VirtualMachine) -> PyRef<Self> {
2036 if let Some(zelf) = num.downcast_ref_if_exact::<Self>(vm) {
2037 zelf.to_owned()
2038 } else {
2039 Self::clone_exact(Self::number_downcast(num), vm)
2040 }
2041 }
2042}
2043
2044#[pyclass]
2045pub trait Iterable: PyPayload {
2046 #[pyslot]
2047 fn slot_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2048 let zelf = zelf
2049 .downcast()
2050 .map_err(|_| vm.new_type_error("unexpected payload for __iter__"))?;
2051 Self::iter(zelf, vm)
2052 }
2053
2054 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult;
2055
2056 fn extend_slots(_slots: &mut PyTypeSlots) {}
2057}
2058
2059#[pyclass(with(Iterable))]
2061pub trait IterNext: PyPayload + Iterable {
2062 #[pyslot]
2063 fn slot_iternext(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
2064 let zelf = zelf
2065 .downcast_ref()
2066 .ok_or_else(|| vm.new_type_error("unexpected payload for __next__"))?;
2067 Self::next(zelf, vm)
2068 }
2069
2070 fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn>;
2071}
2072
2073pub trait SelfIter: PyPayload {}
2074
2075impl<T> Iterable for T
2076where
2077 T: SelfIter,
2078{
2079 #[cold]
2080 fn slot_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2081 let repr = zelf.repr(vm)?;
2082 unreachable!("slot must be overridden for {}", repr.as_wtf8());
2083 }
2084
2085 #[cold]
2086 fn iter(_zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult {
2087 unreachable!("slot_iter is implemented");
2088 }
2089
2090 fn extend_slots(slots: &mut PyTypeSlots) {
2091 let prev = slots.iter.swap(Some(self_iter));
2092 debug_assert!(prev.is_some()); }
2094}