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::{
11 Callee, Either, FromArgs, FuncArgs, ItemDoc, PyComparisonValue, PyMethodDef, PySetterValue,
12 },
13 protocol::{
14 BufferFlags, PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyMappingSlots, PyNumber,
15 PyNumberMethods, PyNumberSlots, PySequence, PySequenceMethods, PySequenceSlots,
16 },
17 types::slot_defs::{SlotAccessor, find_slot_defs_by_name},
18 vm::Context,
19};
20use core::{any::Any, any::TypeId, borrow::Borrow, cmp::Ordering, ops::Deref};
21use crossbeam_utils::atomic::AtomicCell;
22use num_traits::{Signed, ToPrimitive};
23use rustpython_common::wtf8::Wtf8Buf;
24
25pub type DelNeededFunc = fn(&PyObject) -> bool;
27
28pub struct TypeDataSlot {
30 type_id: TypeId,
32 data: Box<dyn Any + Send + Sync>,
33}
34
35impl TypeDataSlot {
36 pub fn new<T: Any + Send + Sync + 'static>(data: T) -> Self {
38 Self {
39 type_id: TypeId::of::<T>(),
40 data: Box::new(data),
41 }
42 }
43
44 #[must_use]
46 pub fn get<T: Any + 'static>(&self) -> Option<&T> {
47 if self.type_id == TypeId::of::<T>() {
48 self.data.downcast_ref()
49 } else {
50 None
51 }
52 }
53
54 pub fn get_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
56 if self.type_id == TypeId::of::<T>() {
57 self.data.downcast_mut()
58 } else {
59 None
60 }
61 }
62}
63
64pub struct TypeDataRef<'a, T: 'static> {
66 guard: PyMappedRwLockReadGuard<'a, T>,
67}
68
69impl<'a, T: Any + 'static> TypeDataRef<'a, T> {
70 #[must_use]
73 pub fn try_new(guard: PyRwLockReadGuard<'a, Option<TypeDataSlot>>) -> Option<Self> {
74 PyRwLockReadGuard::try_map(guard, |opt| opt.as_ref().and_then(|slot| slot.get::<T>()))
75 .ok()
76 .map(|guard| Self { guard })
77 }
78}
79
80impl<T: Any + 'static> core::ops::Deref for TypeDataRef<'_, T> {
81 type Target = T;
82
83 fn deref(&self) -> &Self::Target {
84 &self.guard
85 }
86}
87
88pub struct TypeDataRefMut<'a, T: 'static> {
90 guard: PyMappedRwLockWriteGuard<'a, T>,
91}
92
93impl<'a, T: Any + 'static> TypeDataRefMut<'a, T> {
94 #[must_use]
97 pub fn try_new(guard: PyRwLockWriteGuard<'a, Option<TypeDataSlot>>) -> Option<Self> {
98 PyRwLockWriteGuard::try_map(guard, |opt| {
99 opt.as_mut().and_then(|slot| slot.get_mut::<T>())
100 })
101 .ok()
102 .map(|guard| Self { guard })
103 }
104}
105
106impl<T: Any + 'static> core::ops::Deref for TypeDataRefMut<'_, T> {
107 type Target = T;
108
109 fn deref(&self) -> &Self::Target {
110 &self.guard
111 }
112}
113
114impl<T: Any + 'static> core::ops::DerefMut for TypeDataRefMut<'_, T> {
115 fn deref_mut(&mut self) -> &mut Self::Target {
116 &mut self.guard
117 }
118}
119
120#[macro_export]
121macro_rules! atomic_func {
122 ($x:expr) => {
123 Some($x)
124 };
125}
126
127#[derive(Default)]
130#[non_exhaustive]
131pub struct PyTypeSlots {
132 pub(crate) name: &'static str, pub basicsize: usize,
140 pub itemsize: usize, pub as_number: PyNumberSlots,
146 pub as_sequence: PySequenceSlots,
147 pub as_mapping: PyMappingSlots,
148
149 pub hash: AtomicCell<Option<HashFunc>>,
151 pub call: AtomicCell<Option<GenericMethod>>,
152 pub vectorcall: AtomicCell<Option<VectorCallFunc>>,
153 pub str: AtomicCell<Option<StringifyFunc>>,
154 pub repr: AtomicCell<Option<StringifyFunc>>,
155 pub getattro: AtomicCell<Option<GetattroFunc>>,
156 pub setattro: AtomicCell<Option<SetattroFunc>>,
157
158 pub as_buffer: AtomicCell<Option<AsBufferFunc>>,
160 pub has_release_buffer: AtomicCell<bool>,
163 pub python_release_buffer: AtomicCell<bool>,
165
166 pub richcompare: AtomicCell<Option<RichCompareFunc>>,
169
170 pub iter: AtomicCell<Option<IterFunc>>,
172 pub iternext: AtomicCell<Option<IterNextFunc>>,
173
174 pub methods: &'static [PyMethodDef],
175
176 pub flags: AtomicPyTypeFlags,
179
180 pub doc: ItemDoc,
182
183 pub descr_get: AtomicCell<Option<DescrGetFunc>>,
187 pub descr_set: AtomicCell<Option<DescrSetFunc>>,
188 pub init: AtomicCell<Option<InitFunc>>,
190 pub alloc: AtomicCell<Option<AllocFunc>>,
192 pub new: AtomicCell<Option<NewFunc>>,
193 pub del: AtomicCell<Option<DelFunc>>,
201
202 pub del_needed: AtomicCell<Option<DelNeededFunc>>,
211
212 pub member_count: usize,
214}
215
216impl PyTypeSlots {
217 #[must_use]
218 pub fn new(name: &'static str, flags: PyTypeFlags) -> Self {
219 Self {
220 name,
221 flags: AtomicPyTypeFlags::from_plain(flags),
222 ..Default::default()
223 }
224 }
225
226 #[must_use]
227 pub fn heap_default() -> Self {
228 Self::default()
235 }
236}
237
238impl core::fmt::Debug for PyTypeSlots {
239 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
240 f.write_str("PyTypeSlots")
241 }
242}
243
244bitflagset::bitflagset! {
245 #[derive(Copy, Clone, PartialEq, Eq)]
246 pub struct PyTypeFlags(u64) {
247 const INLINE_VALUES = 2;
248 const MANAGED_WEAKREF = 3;
249 const MANAGED_DICT = 4;
250 const SEQUENCE = 5;
251 const MAPPING = 6;
252 const DISALLOW_INSTANTIATION = 7;
253 const IMMUTABLETYPE = 8;
254 const HEAPTYPE = 9;
255 const BASETYPE = 10;
256 const METHOD_DESCRIPTOR = 17;
257 const IS_ABSTRACT = 20;
258 const _MATCH_SELF = 22;
262 const HAS_DICT = 40;
263 const HAS_WEAKREF = 41;
264 #[cfg(debug_assertions)]
265 const _CREATED_WITH_FLAGS = 63;
266 }
267}
268
269bitflagset::atomic_bitflagset!(
270 pub struct AtomicPyTypeFlags(core::sync::atomic::AtomicU64) on PyTypeFlags
271);
272
273impl PyTypeFlags {
274 pub const HEAP_TYPE: Self = Self::from_slice(&[Self::HEAPTYPE, Self::BASETYPE]);
275
276 pub const HEAP_TYPE_WITH_DICT: Self =
277 Self::from_bits_retain(Self::HEAP_TYPE.bits() | (1u64 << (Self::HAS_DICT as u32)));
278
279 pub const HEAP_TYPE_DICT_IMMUTABLE: Self = Self::from_bits_retain(
280 Self::HEAP_TYPE_WITH_DICT.bits() | (1u64 << (Self::IMMUTABLETYPE as u32)),
281 );
282
283 pub const COLLECTION: Self = Self::from_slice(&[Self::SEQUENCE, Self::MAPPING]);
284}
285
286impl AtomicPyTypeFlags {
287 #[must_use]
288 pub fn load(&self) -> PyTypeFlags {
289 PyTypeFlags::from_bits_retain(self.as_bits().load(core::sync::atomic::Ordering::Acquire))
292 }
293
294 #[must_use]
295 pub fn has_feature(&self, flag: u8) -> bool {
296 self.contains(&flag)
297 }
298
299 pub fn replace_masked(&self, mask: PyTypeFlags, value: PyTypeFlags) {
301 let mask_bits = mask.bits();
302 let value_bits = (value & mask).bits();
303 let _ = self.as_bits().try_update(
304 core::sync::atomic::Ordering::AcqRel,
305 core::sync::atomic::Ordering::Acquire,
306 |old| Some((old & !mask_bits) | value_bits),
307 );
308 }
309
310 pub fn remove_masked(&self, mask: PyTypeFlags) {
312 let _ = self
313 .as_bits()
314 .fetch_and(!mask.bits(), core::sync::atomic::Ordering::AcqRel);
315 }
316}
317
318impl core::ops::BitOrAssign<PyTypeFlags> for AtomicPyTypeFlags {
319 fn bitor_assign(&mut self, rhs: PyTypeFlags) {
320 self.as_bits()
321 .fetch_or(rhs.bits(), core::sync::atomic::Ordering::AcqRel);
322 }
323}
324
325const _: () = assert!(
328 core::mem::size_of::<AtomicPyTypeFlags>()
329 == core::mem::size_of::<core::sync::atomic::AtomicU64>()
330 && core::mem::align_of::<AtomicPyTypeFlags>()
331 == core::mem::align_of::<core::sync::atomic::AtomicU64>()
332);
333
334impl crate::builtins::descriptor::MemberLayout for AtomicPyTypeFlags {
335 const KIND: crate::builtins::descriptor::MemberKind = {
336 if core::mem::size_of::<core::ffi::c_ulong>() == 8 {
337 crate::builtins::descriptor::MemberKind::ULong
338 } else {
339 crate::builtins::descriptor::MemberKind::ULongLong
340 }
341 };
342 const ATOMIC: bool = true;
343}
344
345#[cfg(test)]
346mod tests {
347 #[cfg(debug_assertions)]
348 #[test]
349 fn created_with_flags_bit_roundtrips() {
350 use super::{AtomicPyTypeFlags, PyTypeFlags};
351
352 let flags = PyTypeFlags::from_element(PyTypeFlags::_CREATED_WITH_FLAGS);
353 assert!(flags.contains(&PyTypeFlags::_CREATED_WITH_FLAGS));
354 let atomic = AtomicPyTypeFlags::from_plain(flags);
355 assert!(atomic.contains(&PyTypeFlags::_CREATED_WITH_FLAGS));
356 }
357}
358
359pub(crate) type GenericMethod = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyResult;
360pub(crate) type VectorCallFunc = fn(
365 &PyObject, Vec<PyObjectRef>, usize, Option<&[PyObjectRef]>, &VirtualMachine,
370) -> PyResult;
371pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyHash>;
372pub(crate) type StringifyFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyRef<PyStr>>;
374pub(crate) type GetattroFunc = fn(&PyObject, &Py<PyStr>, &VirtualMachine) -> PyResult;
375pub(crate) type SetattroFunc =
376 fn(&PyObject, &Py<PyStr>, PySetterValue, &VirtualMachine) -> PyResult<()>;
377pub(crate) type AsBufferFunc = fn(&PyObject, BufferFlags, &VirtualMachine) -> PyResult<PyBuffer>;
379pub(crate) type RichCompareFunc = fn(
380 &PyObject,
381 &PyObject,
382 PyComparisonOp,
383 &VirtualMachine,
384) -> PyResult<Either<PyObjectRef, PyComparisonValue>>;
385pub(crate) type IterFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult;
386pub(crate) type IterNextFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyIterReturn>;
387pub(crate) type DescrGetFunc =
388 fn(&PyObject, Option<&PyObject>, Option<&PyObject>, &VirtualMachine) -> PyResult;
389pub(crate) type DescrSetFunc =
390 fn(&PyObject, PyObjectRef, PySetterValue, &VirtualMachine) -> PyResult<()>;
391pub(crate) type AllocFunc = fn(PyTypeRef, usize, &VirtualMachine) -> PyResult;
392pub(crate) type NewFunc = fn(PyTypeRef, FuncArgs, &VirtualMachine) -> PyResult;
393pub(crate) type InitFunc = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyResult<()>;
394pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>;
395
396pub(crate) type SeqLenFunc = fn(PySequence<'_>, &VirtualMachine) -> PyResult<usize>;
398pub(crate) type SeqConcatFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult;
399pub(crate) type SeqRepeatFunc = fn(PySequence<'_>, isize, &VirtualMachine) -> PyResult;
400pub(crate) type SeqItemFunc = fn(PySequence<'_>, isize, &VirtualMachine) -> PyResult;
401pub(crate) type SeqAssItemFunc =
402 fn(PySequence<'_>, isize, Option<PyObjectRef>, &VirtualMachine) -> PyResult<()>;
403pub(crate) type SeqContainsFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult<bool>;
404
405pub(crate) type MapLenFunc = fn(PyMapping<'_>, &VirtualMachine) -> PyResult<usize>;
407pub(crate) type MapSubscriptFunc = fn(PyMapping<'_>, &PyObject, &VirtualMachine) -> PyResult;
408pub(crate) type MapAssSubscriptFunc =
409 fn(PyMapping<'_>, &PyObject, Option<PyObjectRef>, &VirtualMachine) -> PyResult<()>;
410
411pub(crate) fn python_as_buffer(
413 obj: &PyObject,
414 flags: BufferFlags,
415 vm: &VirtualMachine,
416) -> PyResult<PyBuffer> {
417 crate::builtins::memory::buffer_from_python_getbuffer(obj, flags, vm)
418}
419
420pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult<usize> {
422 let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?;
423 let len = ret.try_index(vm)?;
425 let len = len.as_bigint();
426 if len.is_negative() {
427 return Err(vm.new_value_error("__len__() should return >= 0"));
428 }
429 let len = len
430 .to_isize()
431 .ok_or_else(|| vm.new_overflow_error("cannot fit 'int' into an index-sized integer"))?;
432 Ok(len as usize)
433}
434
435pub(crate) fn contains_wrapper(
436 obj: &PyObject,
437 needle: &PyObject,
438 vm: &VirtualMachine,
439) -> PyResult<bool> {
440 let ret = vm.call_special_method(obj, identifier!(vm, __contains__), (needle,))?;
441 ret.try_to_bool(vm)
442}
443
444macro_rules! number_unary_op_wrapper {
445 ($name:ident) => {
446 |a, vm| vm.call_special_method(a.deref(), identifier!(vm, $name), ())
447 };
448}
449macro_rules! number_binary_op_wrapper {
450 ($name:ident) => {
451 |a, b, vm| vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(),))
452 };
453}
454macro_rules! number_binary_right_op_wrapper {
455 ($name:ident) => {
456 |a, b, vm| vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),))
457 };
458}
459macro_rules! number_ternary_op_wrapper {
460 ($name:ident) => {
461 |a, b, c, vm: &VirtualMachine| {
462 if vm.is_none(c) {
463 vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(),))
464 } else {
465 vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(), c.to_owned()))
466 }
467 }
468 };
469}
470macro_rules! number_ternary_right_op_wrapper {
471 ($name:ident) => {
472 |a, b, c, vm: &VirtualMachine| {
473 if vm.is_none(c) {
474 vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),))
475 } else {
476 vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(), c.to_owned()))
477 }
478 }
479 };
480}
481fn getitem_wrapper<K: ToPyObject>(obj: &PyObject, needle: K, vm: &VirtualMachine) -> PyResult {
482 vm.call_special_method(obj, identifier!(vm, __getitem__), (needle,))
483}
484
485fn setitem_wrapper<K: ToPyObject>(
486 obj: &PyObject,
487 needle: K,
488 value: Option<PyObjectRef>,
489 vm: &VirtualMachine,
490) -> PyResult<()> {
491 match value {
492 Some(value) => vm.call_special_method(obj, identifier!(vm, __setitem__), (needle, value)),
493 None => vm.call_special_method(obj, identifier!(vm, __delitem__), (needle,)),
494 }
495 .map(drop)
496}
497
498#[inline(never)]
499fn mapping_setitem_wrapper(
500 mapping: PyMapping<'_>,
501 key: &PyObject,
502 value: Option<PyObjectRef>,
503 vm: &VirtualMachine,
504) -> PyResult<()> {
505 setitem_wrapper(mapping.obj, key, value, vm)
506}
507
508#[inline(never)]
509fn mapping_getitem_wrapper(
510 mapping: PyMapping<'_>,
511 key: &PyObject,
512 vm: &VirtualMachine,
513) -> PyResult {
514 getitem_wrapper(mapping.obj, key, vm)
515}
516
517#[inline(never)]
518fn mapping_len_wrapper(mapping: PyMapping<'_>, vm: &VirtualMachine) -> PyResult<usize> {
519 len_wrapper(mapping.obj, vm)
520}
521
522#[inline(never)]
523fn sequence_len_wrapper(seq: PySequence<'_>, vm: &VirtualMachine) -> PyResult<usize> {
524 len_wrapper(seq.obj, vm)
525}
526
527#[inline(never)]
528fn sequence_getitem_wrapper(seq: PySequence<'_>, i: isize, vm: &VirtualMachine) -> PyResult {
529 getitem_wrapper(seq.obj, i, vm)
530}
531
532#[inline(never)]
533fn sequence_setitem_wrapper(
534 seq: PySequence<'_>,
535 i: isize,
536 value: Option<PyObjectRef>,
537 vm: &VirtualMachine,
538) -> PyResult<()> {
539 setitem_wrapper(seq.obj, i, value, vm)
540}
541
542#[inline(never)]
543fn sequence_contains_wrapper(
544 seq: PySequence<'_>,
545 needle: &PyObject,
546 vm: &VirtualMachine,
547) -> PyResult<bool> {
548 contains_wrapper(seq.obj, needle, vm)
549}
550
551fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
552 let ret = vm.call_special_method(zelf, identifier!(vm, __repr__), ())?;
553 ret.downcast::<PyStr>().map_err(|obj| {
554 vm.new_type_error(format!(
555 "__repr__ returned non-string (type {})",
556 obj.class()
557 ))
558 })
559}
560
561fn str_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
562 let ret = vm.call_special_method(zelf, identifier!(vm, __str__), ())?;
563 ret.downcast::<PyStr>().map_err(|obj| {
564 vm.new_type_error(format!(
565 "__str__ returned non-string (type {})",
566 obj.class()
567 ))
568 })
569}
570
571fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
572 let hash_obj = vm.call_special_method(zelf, identifier!(vm, __hash__), ())?;
573 let py_int = hash_obj
574 .downcast_ref::<PyInt>()
575 .ok_or_else(|| vm.new_type_error("__hash__ method should return an integer"))?;
576 let big_int = py_int.as_bigint();
577 let hash = big_int
578 .to_i64()
579 .map_or_else(|| hash_bigint(big_int), fix_sentinel);
580 Ok(hash)
581}
582
583pub fn hash_not_implemented(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
585 Err(vm.new_type_error(format!("unhashable type: '{}'", zelf.class().slot_name())))
586}
587
588fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
589 vm.with_recursion("while calling a Python object", || {
592 vm.call_special_method(zelf, identifier!(vm, __call__), args)
593 })
594}
595
596fn getattro_wrapper(zelf: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
598 let __getattribute__ = identifier!(vm, __getattribute__);
599 let __getattr__ = identifier!(vm, __getattr__);
600 let class = zelf.class();
601 let Some(getattr) = class.get_attr(__getattr__) else {
603 return vm.call_special_method(zelf, __getattribute__, (name.to_owned(),));
604 };
605 let generic = class
606 .get_attr(__getattribute__)
607 .is_some_and(|getattribute| {
608 vm.ctx
609 .types
610 .object_type
611 .get_attr(__getattribute__)
612 .is_some_and(|generic| getattribute.is(&generic))
613 });
614 let result = if generic {
616 zelf.generic_getattr_opt(name, None, vm)
617 } else {
618 vm.call_special_method(zelf, __getattribute__, (name.to_owned(),))
619 .map(Some)
620 };
621 match result {
622 Ok(Some(value)) => return Ok(value),
623 Ok(None) => {}
624 Err(e) if e.fast_isinstance(vm.ctx.exceptions.attribute_error) => {}
625 Err(e) => return Err(e),
626 }
627 if getattr
629 .class()
630 .slots
631 .flags
632 .has_feature(PyTypeFlags::METHOD_DESCRIPTOR)
633 {
634 getattr.call((zelf.to_owned(), name.to_owned()), vm)
635 } else {
636 let bound = vm.call_get_descriptor(&getattr, zelf).transpose()?;
637 bound
638 .as_ref()
639 .unwrap_or(&getattr)
640 .call((name.to_owned(),), vm)
641 }
642}
643
644pub(crate) fn hackcheck_setattro(
647 obj: &PyObject,
648 func: SetattroFunc,
649 what: &str,
650 vm: &VirtualMachine,
651) -> PyResult<()> {
652 let Some(_typ) = obj.downcast_ref::<PyType>() else {
653 return Ok(());
654 };
655 let obj_cls = obj.class();
656 let obj_setattro = obj_cls.slots.setattro.load();
657
658 let mut defining = obj_cls.to_owned();
659 {
660 let mro = obj_cls.mro.read();
661 for base in mro.iter().rev() {
662 let base_setattro = base.slots.setattro.load();
663 if is_slot_tp_setattro(base_setattro) {
664 continue;
665 } else if setattro_eq(base_setattro, obj_setattro) {
666 defining = base.clone();
667 break;
668 }
669 }
670 }
671
672 let mut base = Some(defining);
673 while let Some(b) = base {
674 let b_setattro = b.slots.setattro.load();
675 if setattro_eq(b_setattro, Some(func)) {
676 return Ok(());
677 } else if !is_slot_tp_setattro(b_setattro) {
678 return Err(vm.new_type_error(format!(
679 "can't apply this {what} to {} object",
680 obj_cls.slot_name()
681 )));
682 }
683 base = b.base.load_owned();
684 }
685 Ok(())
686}
687
688fn is_slot_tp_setattro(f: Option<SetattroFunc>) -> bool {
689 f.is_some_and(|f| fn_addr(f) == fn_addr(setattro_wrapper as SetattroFunc))
690}
691
692fn setattro_eq(a: Option<SetattroFunc>, b: Option<SetattroFunc>) -> bool {
693 match (a, b) {
694 (Some(a), Some(b)) => fn_addr(a) == fn_addr(b),
695 (None, None) => true,
696 _ => false,
697 }
698}
699
700fn setattro_wrapper(
701 zelf: &PyObject,
702 name: &Py<PyStr>,
703 value: PySetterValue,
704 vm: &VirtualMachine,
705) -> PyResult<()> {
706 let name = name.to_owned();
707 match value {
708 PySetterValue::Assign(value) => {
709 vm.call_special_method(zelf, identifier!(vm, __setattr__), (name, value))?;
710 }
711 PySetterValue::Delete => {
712 vm.call_special_method(zelf, identifier!(vm, __delattr__), (name,))?;
713 }
714 };
715 Ok(())
716}
717
718pub(crate) fn richcompare_wrapper(
719 zelf: &PyObject,
720 other: &PyObject,
721 op: PyComparisonOp,
722 vm: &VirtualMachine,
723) -> PyResult<Either<PyObjectRef, PyComparisonValue>> {
724 match vm.get_special_method(zelf, op.method_name(&vm.ctx))? {
728 Some(meth) => meth.invoke((other.to_owned(),), vm).map(Either::A),
729 None => Ok(Either::B(PyComparisonValue::NotImplemented)),
730 }
731}
732
733fn iter_wrapper(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
734 let cls = zelf.class();
736 let iter_attr = cls.get_attr(identifier!(vm, __iter__));
737 match iter_attr {
738 Some(attr) if vm.is_none(&attr) => {
739 Err(vm.new_type_error(format!("'{}' object is not iterable", cls.slot_name())))
740 }
741 _ => vm.call_special_method(&zelf, identifier!(vm, __iter__), ()),
742 }
743}
744
745fn bool_wrapper(num: PyNumber<'_>, vm: &VirtualMachine) -> PyResult<bool> {
746 let result = vm.call_special_method(num.obj, identifier!(vm, __bool__), ())?;
747 if !result.class().is(vm.ctx.types.bool_type) {
749 return Err(vm.new_type_error(format!(
750 "__bool__ should return bool, returned {}",
751 result.class().name()
752 )));
753 }
754 Ok(crate::builtins::bool_::get_value(&result))
755}
756
757#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
759const fn self_iter(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult {
760 Ok(zelf)
761}
762
763fn iternext_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
764 PyIterReturn::from_pyresult(
765 vm.call_special_method(zelf, identifier!(vm, __next__), ()),
766 vm,
767 )
768}
769
770fn descr_get_wrapper(
771 zelf: &PyObject,
772 obj: Option<&PyObject>,
773 cls: Option<&PyObject>,
774 vm: &VirtualMachine,
775) -> PyResult {
776 vm.with_recursion("while calling a Python object", || {
779 vm.call_special_method(
780 zelf,
781 identifier!(vm, __get__),
782 (obj.map(PyObject::to_owned), cls.map(PyObject::to_owned)),
783 )
784 })
785}
786
787fn descr_set_wrapper(
788 zelf: &PyObject,
789 obj: PyObjectRef,
790 value: PySetterValue,
791 vm: &VirtualMachine,
792) -> PyResult<()> {
793 match value {
794 PySetterValue::Assign(val) => {
795 vm.call_special_method(zelf, identifier!(vm, __set__), (obj, val))
796 }
797 PySetterValue::Delete => vm.call_special_method(zelf, identifier!(vm, __delete__), (obj,)),
798 }
799 .map(drop)
800}
801
802fn init_wrapper(obj: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
803 let res = vm.call_special_method(obj, identifier!(vm, __init__), args)?;
804 if !vm.is_none(&res) {
805 return Err(vm.new_type_error(format!(
806 "__init__() should return None, not '{:.200}'",
807 res.class().name()
808 )));
809 }
810 Ok(())
811}
812
813pub(crate) fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
814 let new = cls.as_object().get_attr(identifier!(vm, __new__), vm)?;
815 args.prepend_arg(cls.into());
816 new.call(args, vm)
817}
818
819fn del_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
820 vm.call_special_method(zelf, identifier!(vm, __del__), ())?;
821 Ok(())
822}
823
824enum SlotLookupResult<T> {
826 NativeSlot(T),
828 PythonMethod,
831 NotFound,
834}
835
836impl PyType {
837 pub(crate) fn update_slot<const ADD: bool>(&self, name: &'static PyStrInterned, ctx: &Context) {
842 debug_assert!(name.as_str().starts_with("__"));
843 debug_assert!(name.as_str().ends_with("__"));
844
845 let defs: Vec<_> = find_slot_defs_by_name(name.as_str()).collect();
848 for def in defs {
849 self.update_one_slot::<ADD>(def.accessor, name, ctx);
850 }
851
852 self.update_subclasses::<ADD>(name, ctx);
854 }
855
856 fn update_subclasses<const ADD: bool>(&self, name: &'static PyStrInterned, ctx: &Context) {
859 let subclasses = self.subclasses.read();
860 for weak_ref in subclasses.iter() {
861 let Some(subclass) = weak_ref.upgrade() else {
862 continue;
863 };
864 let Some(subclass) = subclass.downcast_ref::<Self>() else {
865 continue;
866 };
867
868 if subclass.attributes.contains(name) {
870 continue;
871 }
872
873 for def in find_slot_defs_by_name(name.as_str()) {
875 subclass.update_one_slot::<ADD>(def.accessor, name, ctx);
876 }
877
878 subclass.update_subclasses::<ADD>(name, ctx);
880 }
881 }
882
883 fn update_one_slot<const ADD: bool>(
885 &self,
886 accessor: SlotAccessor,
887 name: &'static PyStrInterned,
888 ctx: &Context,
889 ) {
890 use crate::builtins::descriptor::SlotFunc;
891
892 macro_rules! update_main_slot {
894 ($slot:ident, $wrapper:expr, $variant:ident) => {{
895 if ADD {
896 match self.lookup_slot_in_mro(name, ctx, |sf| {
897 if let SlotFunc::$variant(f) = sf {
898 Some(*f)
899 } else {
900 None
901 }
902 }) {
903 SlotLookupResult::NativeSlot(func) => {
904 self.slots.$slot.store(Some(func));
905 }
906 SlotLookupResult::PythonMethod => {
907 self.slots.$slot.store(Some($wrapper));
908 }
909 SlotLookupResult::NotFound => {
910 accessor.inherit_from_mro(self);
911 }
912 }
913 } else {
914 accessor.inherit_from_mro(self);
915 }
916 }};
917 }
918
919 macro_rules! update_sub_slot {
921 ($group:ident, $slot:ident, $wrapper:expr, $variant:ident) => {{
922 let inherit_this_field = || {
928 let mro = self.mro.read();
929 let inherited = mro[1..]
930 .iter()
931 .find_map(|cls| cls.slots.$group.$slot.load());
932 self.slots.$group.$slot.store(inherited);
933 };
934 if ADD {
935 let has_own = {
940 let mut result = self.attributes.contains(name);
942 if !result
945 && (stringify!($slot) == "ass_item"
946 || stringify!($slot) == "ass_subscript")
947 {
948 let setitem = ctx.intern_str("__setitem__");
949 let delitem = ctx.intern_str("__delitem__");
950 result = self.attributes.contains(setitem)
951 || self.attributes.contains(delitem);
952 }
953 result
954 };
955 let store_wrapper = || self.slots.$group.$slot.store(Some($wrapper));
962 if has_own {
963 store_wrapper();
964 } else {
965 match self.lookup_slot_in_mro(name, ctx, |sf| {
966 if let SlotFunc::$variant(f) = sf {
967 Some(*f)
968 } else {
969 None
970 }
971 }) {
972 SlotLookupResult::NativeSlot(func) => {
973 self.slots.$group.$slot.store(Some(func));
974 }
975 SlotLookupResult::PythonMethod => {
976 store_wrapper();
977 }
978 SlotLookupResult::NotFound => {
979 inherit_this_field();
980 }
981 }
982 }
983 } else {
984 inherit_this_field();
985 }
986 }};
987 }
988
989 match accessor {
990 SlotAccessor::TpRepr => update_main_slot!(repr, repr_wrapper, Repr),
992 SlotAccessor::TpStr => update_main_slot!(str, str_wrapper, Str),
993 SlotAccessor::TpHash => {
994 if ADD {
996 let method = self.attributes.get(name).or_else(|| {
997 self.mro
998 .read()
999 .iter()
1000 .find_map(|cls| cls.attributes.get(name))
1001 });
1002
1003 if method.as_ref().is_some_and(|m| m.is(&ctx.none)) {
1004 self.slots.hash.store(Some(hash_not_implemented));
1005 } else {
1006 match self.lookup_slot_in_mro(name, ctx, |sf| {
1007 if let SlotFunc::Hash(f) = sf {
1008 Some(*f)
1009 } else {
1010 None
1011 }
1012 }) {
1013 SlotLookupResult::NativeSlot(func) => {
1014 self.slots.hash.store(Some(func));
1015 }
1016 SlotLookupResult::PythonMethod => {
1017 self.slots.hash.store(Some(hash_wrapper));
1018 }
1019 SlotLookupResult::NotFound => {
1020 accessor.inherit_from_mro(self);
1021 }
1022 }
1023 }
1024 } else {
1025 accessor.inherit_from_mro(self);
1026 }
1027 }
1028 SlotAccessor::TpCall => {
1029 update_main_slot!(call, call_wrapper, Call);
1030 if ADD {
1033 self.slots.vectorcall.store(None);
1034 }
1035 }
1036 SlotAccessor::TpIter => update_main_slot!(iter, iter_wrapper, Iter),
1037 SlotAccessor::TpIternext => update_main_slot!(iternext, iternext_wrapper, IterNext),
1038 SlotAccessor::TpInit => {
1039 update_main_slot!(init, init_wrapper, Init);
1040 if ADD {
1041 self.slots.vectorcall.store(None);
1042 }
1043 }
1044 SlotAccessor::TpNew => {
1045 let needs_wrapper = if ADD && self.attributes.contains(name) {
1053 true
1054 } else {
1055 self.mro.read()[1..]
1057 .iter()
1058 .find(|cls| cls.attributes.contains(name))
1059 .is_some_and(|cls| {
1060 cls.slots.new.load().map(|f| fn_addr(f))
1061 == Some(fn_addr(new_wrapper as NewFunc))
1062 })
1063 };
1064 if needs_wrapper {
1065 self.slots.new.store(Some(new_wrapper));
1066 self.slots.vectorcall.store(None);
1067 } else {
1068 let inherited = self.base.deref().and_then(|base| base.slots.new.load());
1069 self.slots.new.store(inherited);
1070 }
1071 }
1072 SlotAccessor::TpDel => update_main_slot!(del, del_wrapper, Del),
1073 SlotAccessor::TpGetattro => {
1074 let __getattr__ = identifier!(ctx, __getattr__);
1078 let has_getattr = {
1079 self.attributes.contains(__getattr__)
1081 || self
1082 .mro
1083 .read()
1084 .iter()
1085 .skip(1)
1086 .any(|cls| cls.attributes.contains(__getattr__))
1087 };
1088
1089 if has_getattr {
1090 self.slots.getattro.store(Some(getattro_wrapper));
1092 } else if ADD {
1093 match self.lookup_slot_in_mro(name, ctx, |sf| {
1094 if let SlotFunc::GetAttro(f) = sf {
1095 Some(*f)
1096 } else {
1097 None
1098 }
1099 }) {
1100 SlotLookupResult::NativeSlot(func) => {
1101 self.slots.getattro.store(Some(func));
1102 }
1103 SlotLookupResult::PythonMethod => {
1104 self.slots.getattro.store(Some(getattro_wrapper));
1105 }
1106 SlotLookupResult::NotFound => {
1107 accessor.inherit_from_mro(self);
1108 }
1109 }
1110 } else {
1111 accessor.inherit_from_mro(self);
1112 }
1113 }
1114 SlotAccessor::TpSetattro => {
1115 let extract = |sf: &SlotFunc| match sf {
1122 SlotFunc::SetAttro(f) | SlotFunc::DelAttro(f) => Some(*f),
1123 _ => None,
1124 };
1125 let setattr = self.lookup_slot_in_mro(identifier!(ctx, __setattr__), ctx, extract);
1126 let delattr = self.lookup_slot_in_mro(identifier!(ctx, __delattr__), ctx, extract);
1127 use SlotLookupResult::{NativeSlot, NotFound, PythonMethod};
1128 match (setattr, delattr) {
1129 (PythonMethod, _) | (_, PythonMethod) => {
1130 self.slots.setattro.store(Some(setattro_wrapper));
1131 }
1132 (NativeSlot(set), NativeSlot(del)) => {
1133 let func = if fn_addr(set) == fn_addr(del) {
1134 set
1135 } else {
1136 setattro_wrapper
1137 };
1138 self.slots.setattro.store(Some(func));
1139 }
1140 (NativeSlot(func), NotFound) | (NotFound, NativeSlot(func)) => {
1141 self.slots.setattro.store(Some(func));
1142 }
1143 (NotFound, NotFound) => {
1144 accessor.inherit_from_mro(self);
1145 }
1146 }
1147 }
1148 SlotAccessor::TpDescrGet => update_main_slot!(descr_get, descr_get_wrapper, DescrGet),
1149 SlotAccessor::TpDescrSet => {
1150 let extract = |sf: &SlotFunc| match sf {
1157 SlotFunc::DescrSet(f) | SlotFunc::DescrDel(f) => Some(*f),
1158 _ => None,
1159 };
1160 let set = self.lookup_slot_in_mro(identifier!(ctx, __set__), ctx, extract);
1161 let delete = self.lookup_slot_in_mro(identifier!(ctx, __delete__), ctx, extract);
1162 use SlotLookupResult::{NativeSlot, NotFound, PythonMethod};
1163 match (set, delete) {
1164 (PythonMethod, _) | (_, PythonMethod) => {
1165 self.slots.descr_set.store(Some(descr_set_wrapper));
1166 }
1167 (NativeSlot(set), NativeSlot(delete)) => {
1168 let func = if fn_addr(set) == fn_addr(delete) {
1169 set
1170 } else {
1171 descr_set_wrapper
1172 };
1173 self.slots.descr_set.store(Some(func));
1174 }
1175 (NativeSlot(func), NotFound) | (NotFound, NativeSlot(func)) => {
1176 self.slots.descr_set.store(Some(func));
1177 }
1178 (NotFound, NotFound) => {
1179 accessor.inherit_from_mro(self);
1180 }
1181 }
1182 }
1183
1184 SlotAccessor::TpRichcompare => {
1186 if ADD {
1187 let cmp_names = [
1191 identifier!(ctx, __eq__),
1192 identifier!(ctx, __ne__),
1193 identifier!(ctx, __lt__),
1194 identifier!(ctx, __le__),
1195 identifier!(ctx, __gt__),
1196 identifier!(ctx, __ge__),
1197 ];
1198
1199 let has_python_cmp = {
1200 cmp_names.iter().any(|n| self.attributes.contains(n))
1202 || self.mro.read()[1..].iter().any(|cls| {
1203 cmp_names.iter().any(|n| {
1204 cls.attributes.get(n).is_some_and(|attr| {
1205 !attr.class().is(ctx.types.wrapper_descriptor_type)
1207 && !attr.class().is(ctx.types.method_descriptor_type)
1208 && !attr
1209 .class()
1210 .is(ctx.types.classmethod_descriptor_type)
1211 })
1212 })
1213 })
1214 };
1215
1216 if has_python_cmp {
1217 self.slots.richcompare.store(Some(richcompare_wrapper));
1219 } else {
1220 match self.lookup_slot_in_mro(name, ctx, |sf| {
1221 if let SlotFunc::RichCompare(f, _) = sf {
1222 Some(*f)
1223 } else {
1224 None
1225 }
1226 }) {
1227 SlotLookupResult::NativeSlot(func) => {
1228 self.slots.richcompare.store(Some(func));
1229 }
1230 SlotLookupResult::PythonMethod => {
1231 self.slots.richcompare.store(Some(richcompare_wrapper));
1232 }
1233 SlotLookupResult::NotFound => {
1234 accessor.inherit_from_mro(self);
1235 }
1236 }
1237 }
1238 } else {
1239 accessor.inherit_from_mro(self);
1240 }
1241 }
1242
1243 SlotAccessor::NbAdd => {
1245 if name.as_str() == "__radd__" {
1246 update_sub_slot!(
1247 as_number,
1248 right_add,
1249 number_binary_right_op_wrapper!(__radd__),
1250 NumBinary
1251 )
1252 } else {
1253 update_sub_slot!(
1254 as_number,
1255 add,
1256 number_binary_op_wrapper!(__add__),
1257 NumBinary
1258 )
1259 }
1260 }
1261 SlotAccessor::NbInplaceAdd => {
1262 update_sub_slot!(
1263 as_number,
1264 inplace_add,
1265 number_binary_op_wrapper!(__iadd__),
1266 NumBinary
1267 )
1268 }
1269 SlotAccessor::NbSubtract => {
1270 if name.as_str() == "__rsub__" {
1271 update_sub_slot!(
1272 as_number,
1273 right_subtract,
1274 number_binary_right_op_wrapper!(__rsub__),
1275 NumBinary
1276 )
1277 } else {
1278 update_sub_slot!(
1279 as_number,
1280 subtract,
1281 number_binary_op_wrapper!(__sub__),
1282 NumBinary
1283 )
1284 }
1285 }
1286 SlotAccessor::NbInplaceSubtract => {
1287 update_sub_slot!(
1288 as_number,
1289 inplace_subtract,
1290 number_binary_op_wrapper!(__isub__),
1291 NumBinary
1292 )
1293 }
1294 SlotAccessor::NbMultiply => {
1295 if name.as_str() == "__rmul__" {
1296 update_sub_slot!(
1297 as_number,
1298 right_multiply,
1299 number_binary_right_op_wrapper!(__rmul__),
1300 NumBinary
1301 )
1302 } else {
1303 update_sub_slot!(
1304 as_number,
1305 multiply,
1306 number_binary_op_wrapper!(__mul__),
1307 NumBinary
1308 )
1309 }
1310 }
1311 SlotAccessor::NbInplaceMultiply => {
1312 update_sub_slot!(
1313 as_number,
1314 inplace_multiply,
1315 number_binary_op_wrapper!(__imul__),
1316 NumBinary
1317 )
1318 }
1319 SlotAccessor::NbRemainder => {
1320 if name.as_str() == "__rmod__" {
1321 update_sub_slot!(
1322 as_number,
1323 right_remainder,
1324 number_binary_right_op_wrapper!(__rmod__),
1325 NumBinary
1326 )
1327 } else {
1328 update_sub_slot!(
1329 as_number,
1330 remainder,
1331 number_binary_op_wrapper!(__mod__),
1332 NumBinary
1333 )
1334 }
1335 }
1336 SlotAccessor::NbInplaceRemainder => {
1337 update_sub_slot!(
1338 as_number,
1339 inplace_remainder,
1340 number_binary_op_wrapper!(__imod__),
1341 NumBinary
1342 )
1343 }
1344 SlotAccessor::NbDivmod => {
1345 if name.as_str() == "__rdivmod__" {
1346 update_sub_slot!(
1347 as_number,
1348 right_divmod,
1349 number_binary_right_op_wrapper!(__rdivmod__),
1350 NumBinary
1351 )
1352 } else {
1353 update_sub_slot!(
1354 as_number,
1355 divmod,
1356 number_binary_op_wrapper!(__divmod__),
1357 NumBinary
1358 )
1359 }
1360 }
1361 SlotAccessor::NbPower => {
1362 if name.as_str() == "__rpow__" {
1363 update_sub_slot!(
1364 as_number,
1365 right_power,
1366 number_ternary_right_op_wrapper!(__rpow__),
1367 NumTernary
1368 )
1369 } else {
1370 update_sub_slot!(
1371 as_number,
1372 power,
1373 number_ternary_op_wrapper!(__pow__),
1374 NumTernary
1375 )
1376 }
1377 }
1378 SlotAccessor::NbInplacePower => {
1379 update_sub_slot!(
1380 as_number,
1381 inplace_power,
1382 number_ternary_op_wrapper!(__ipow__),
1383 NumTernary
1384 )
1385 }
1386 SlotAccessor::NbFloorDivide => {
1387 if name.as_str() == "__rfloordiv__" {
1388 update_sub_slot!(
1389 as_number,
1390 right_floor_divide,
1391 number_binary_right_op_wrapper!(__rfloordiv__),
1392 NumBinary
1393 )
1394 } else {
1395 update_sub_slot!(
1396 as_number,
1397 floor_divide,
1398 number_binary_op_wrapper!(__floordiv__),
1399 NumBinary
1400 )
1401 }
1402 }
1403 SlotAccessor::NbInplaceFloorDivide => {
1404 update_sub_slot!(
1405 as_number,
1406 inplace_floor_divide,
1407 number_binary_op_wrapper!(__ifloordiv__),
1408 NumBinary
1409 )
1410 }
1411 SlotAccessor::NbTrueDivide => {
1412 if name.as_str() == "__rtruediv__" {
1413 update_sub_slot!(
1414 as_number,
1415 right_true_divide,
1416 number_binary_right_op_wrapper!(__rtruediv__),
1417 NumBinary
1418 )
1419 } else {
1420 update_sub_slot!(
1421 as_number,
1422 true_divide,
1423 number_binary_op_wrapper!(__truediv__),
1424 NumBinary
1425 )
1426 }
1427 }
1428 SlotAccessor::NbInplaceTrueDivide => {
1429 update_sub_slot!(
1430 as_number,
1431 inplace_true_divide,
1432 number_binary_op_wrapper!(__itruediv__),
1433 NumBinary
1434 )
1435 }
1436 SlotAccessor::NbMatrixMultiply => {
1437 if name.as_str() == "__rmatmul__" {
1438 update_sub_slot!(
1439 as_number,
1440 right_matrix_multiply,
1441 number_binary_right_op_wrapper!(__rmatmul__),
1442 NumBinary
1443 )
1444 } else {
1445 update_sub_slot!(
1446 as_number,
1447 matrix_multiply,
1448 number_binary_op_wrapper!(__matmul__),
1449 NumBinary
1450 )
1451 }
1452 }
1453 SlotAccessor::NbInplaceMatrixMultiply => {
1454 update_sub_slot!(
1455 as_number,
1456 inplace_matrix_multiply,
1457 number_binary_op_wrapper!(__imatmul__),
1458 NumBinary
1459 )
1460 }
1461
1462 SlotAccessor::NbLshift => {
1464 if name.as_str() == "__rlshift__" {
1465 update_sub_slot!(
1466 as_number,
1467 right_lshift,
1468 number_binary_right_op_wrapper!(__rlshift__),
1469 NumBinary
1470 )
1471 } else {
1472 update_sub_slot!(
1473 as_number,
1474 lshift,
1475 number_binary_op_wrapper!(__lshift__),
1476 NumBinary
1477 )
1478 }
1479 }
1480 SlotAccessor::NbInplaceLshift => {
1481 update_sub_slot!(
1482 as_number,
1483 inplace_lshift,
1484 number_binary_op_wrapper!(__ilshift__),
1485 NumBinary
1486 )
1487 }
1488 SlotAccessor::NbRshift => {
1489 if name.as_str() == "__rrshift__" {
1490 update_sub_slot!(
1491 as_number,
1492 right_rshift,
1493 number_binary_right_op_wrapper!(__rrshift__),
1494 NumBinary
1495 )
1496 } else {
1497 update_sub_slot!(
1498 as_number,
1499 rshift,
1500 number_binary_op_wrapper!(__rshift__),
1501 NumBinary
1502 )
1503 }
1504 }
1505 SlotAccessor::NbInplaceRshift => {
1506 update_sub_slot!(
1507 as_number,
1508 inplace_rshift,
1509 number_binary_op_wrapper!(__irshift__),
1510 NumBinary
1511 )
1512 }
1513 SlotAccessor::NbAnd => {
1514 if name.as_str() == "__rand__" {
1515 update_sub_slot!(
1516 as_number,
1517 right_and,
1518 number_binary_right_op_wrapper!(__rand__),
1519 NumBinary
1520 )
1521 } else {
1522 update_sub_slot!(
1523 as_number,
1524 and,
1525 number_binary_op_wrapper!(__and__),
1526 NumBinary
1527 )
1528 }
1529 }
1530 SlotAccessor::NbInplaceAnd => {
1531 update_sub_slot!(
1532 as_number,
1533 inplace_and,
1534 number_binary_op_wrapper!(__iand__),
1535 NumBinary
1536 )
1537 }
1538 SlotAccessor::NbXor => {
1539 if name.as_str() == "__rxor__" {
1540 update_sub_slot!(
1541 as_number,
1542 right_xor,
1543 number_binary_right_op_wrapper!(__rxor__),
1544 NumBinary
1545 )
1546 } else {
1547 update_sub_slot!(
1548 as_number,
1549 xor,
1550 number_binary_op_wrapper!(__xor__),
1551 NumBinary
1552 )
1553 }
1554 }
1555 SlotAccessor::NbInplaceXor => {
1556 update_sub_slot!(
1557 as_number,
1558 inplace_xor,
1559 number_binary_op_wrapper!(__ixor__),
1560 NumBinary
1561 )
1562 }
1563 SlotAccessor::NbOr => {
1564 if name.as_str() == "__ror__" {
1565 update_sub_slot!(
1566 as_number,
1567 right_or,
1568 number_binary_right_op_wrapper!(__ror__),
1569 NumBinary
1570 )
1571 } else {
1572 update_sub_slot!(as_number, or, number_binary_op_wrapper!(__or__), NumBinary)
1573 }
1574 }
1575 SlotAccessor::NbInplaceOr => {
1576 update_sub_slot!(
1577 as_number,
1578 inplace_or,
1579 number_binary_op_wrapper!(__ior__),
1580 NumBinary
1581 )
1582 }
1583
1584 SlotAccessor::NbNegative => {
1586 update_sub_slot!(
1587 as_number,
1588 negative,
1589 number_unary_op_wrapper!(__neg__),
1590 NumUnary
1591 )
1592 }
1593 SlotAccessor::NbPositive => {
1594 update_sub_slot!(
1595 as_number,
1596 positive,
1597 number_unary_op_wrapper!(__pos__),
1598 NumUnary
1599 )
1600 }
1601 SlotAccessor::NbAbsolute => {
1602 update_sub_slot!(
1603 as_number,
1604 absolute,
1605 number_unary_op_wrapper!(__abs__),
1606 NumUnary
1607 )
1608 }
1609 SlotAccessor::NbInvert => {
1610 update_sub_slot!(
1611 as_number,
1612 invert,
1613 number_unary_op_wrapper!(__invert__),
1614 NumUnary
1615 )
1616 }
1617 SlotAccessor::NbBool => {
1618 update_sub_slot!(as_number, boolean, bool_wrapper, NumBoolean)
1619 }
1620 SlotAccessor::NbInt => {
1621 update_sub_slot!(as_number, int, number_unary_op_wrapper!(__int__), NumUnary)
1622 }
1623 SlotAccessor::NbFloat => {
1624 update_sub_slot!(
1625 as_number,
1626 float,
1627 number_unary_op_wrapper!(__float__),
1628 NumUnary
1629 )
1630 }
1631 SlotAccessor::NbIndex => {
1632 update_sub_slot!(
1633 as_number,
1634 index,
1635 number_unary_op_wrapper!(__index__),
1636 NumUnary
1637 )
1638 }
1639
1640 SlotAccessor::SqLength => {
1642 update_sub_slot!(as_sequence, length, sequence_len_wrapper, SeqLength)
1643 }
1644 SlotAccessor::SqConcat => {
1645 let concat = match self.lookup_slot_in_mro(name, ctx, |sf| {
1647 if let SlotFunc::SeqConcat(f) = sf {
1648 Some(*f)
1649 } else {
1650 None
1651 }
1652 }) {
1653 SlotLookupResult::NativeSlot(func) => Some(func),
1654 SlotLookupResult::PythonMethod | SlotLookupResult::NotFound => None,
1655 };
1656 self.slots.as_sequence.concat.store(concat);
1657 }
1658 SlotAccessor::SqInplaceConcat if !ADD => {
1659 accessor.inherit_from_mro(self);
1662 }
1663 SlotAccessor::SqRepeat | SlotAccessor::SqInplaceRepeat => {
1664 let (names, field) = if matches!(accessor, SlotAccessor::SqRepeat) {
1667 (
1668 &[identifier!(ctx, __mul__), identifier!(ctx, __rmul__)][..],
1669 &self.slots.as_sequence.repeat,
1670 )
1671 } else {
1672 (
1673 &[identifier!(ctx, __imul__)][..],
1674 &self.slots.as_sequence.inplace_repeat,
1675 )
1676 };
1677 let mut repeat = None;
1678 for &name in names {
1679 match self.lookup_slot_in_mro(name, ctx, |sf| {
1680 if let SlotFunc::SeqRepeat(f) = sf {
1681 Some(*f)
1682 } else {
1683 None
1684 }
1685 }) {
1686 SlotLookupResult::NativeSlot(func) => repeat = repeat.or(Some(func)),
1687 SlotLookupResult::PythonMethod => {
1688 repeat = None;
1689 break;
1690 }
1691 SlotLookupResult::NotFound => {}
1692 }
1693 }
1694 field.store(repeat);
1695 }
1696 SlotAccessor::SqItem => {
1697 update_sub_slot!(as_sequence, item, sequence_getitem_wrapper, SeqItem)
1698 }
1699 SlotAccessor::SqAssItem => {
1700 if ADD {
1702 let has_own = {
1703 let setitem = ctx.intern_str("__setitem__");
1704 let delitem = ctx.intern_str("__delitem__");
1705 self.attributes.contains(setitem) || self.attributes.contains(delitem)
1706 };
1707 if has_own {
1708 self.slots
1709 .as_sequence
1710 .ass_item
1711 .store(Some(sequence_setitem_wrapper));
1712 } else {
1713 match self.lookup_slot_in_mro(name, ctx, |sf| match sf {
1714 SlotFunc::SeqSetItem(f) | SlotFunc::SeqDelItem(f) => Some(*f),
1715 _ => None,
1716 }) {
1717 SlotLookupResult::NativeSlot(func) => {
1718 self.slots.as_sequence.ass_item.store(Some(func));
1719 }
1720 SlotLookupResult::PythonMethod => {
1721 self.slots
1722 .as_sequence
1723 .ass_item
1724 .store(Some(sequence_setitem_wrapper));
1725 }
1726 SlotLookupResult::NotFound => {
1727 accessor.inherit_from_mro(self);
1728 }
1729 }
1730 }
1731 } else {
1732 accessor.inherit_from_mro(self);
1733 }
1734 }
1735 SlotAccessor::SqContains => {
1736 update_sub_slot!(
1737 as_sequence,
1738 contains,
1739 sequence_contains_wrapper,
1740 SeqContains
1741 )
1742 }
1743
1744 SlotAccessor::MpLength => {
1746 update_sub_slot!(as_mapping, length, mapping_len_wrapper, MapLength)
1747 }
1748 SlotAccessor::MpSubscript => {
1749 update_sub_slot!(as_mapping, subscript, mapping_getitem_wrapper, MapSubscript)
1750 }
1751 SlotAccessor::MpAssSubscript => {
1752 if ADD {
1754 let has_own = {
1755 let setitem = ctx.intern_str("__setitem__");
1756 let delitem = ctx.intern_str("__delitem__");
1757 self.attributes.contains(setitem) || self.attributes.contains(delitem)
1758 };
1759 if has_own {
1760 self.slots
1761 .as_mapping
1762 .ass_subscript
1763 .store(Some(mapping_setitem_wrapper));
1764 } else {
1765 match self.lookup_slot_in_mro(name, ctx, |sf| match sf {
1766 SlotFunc::MapSetSubscript(f) | SlotFunc::MapDelSubscript(f) => Some(*f),
1767 _ => None,
1768 }) {
1769 SlotLookupResult::NativeSlot(func) => {
1770 self.slots.as_mapping.ass_subscript.store(Some(func));
1771 }
1772 SlotLookupResult::PythonMethod => {
1773 self.slots
1774 .as_mapping
1775 .ass_subscript
1776 .store(Some(mapping_setitem_wrapper));
1777 }
1778 SlotLookupResult::NotFound => {
1779 accessor.inherit_from_mro(self);
1780 }
1781 }
1782 }
1783 } else {
1784 accessor.inherit_from_mro(self);
1785 }
1786 }
1787
1788 SlotAccessor::BfGetBuffer => {
1790 if ADD {
1791 match self.lookup_slot_in_mro(name, ctx, |sf| {
1792 if let SlotFunc::GetBuffer(f) = sf {
1793 Some(*f)
1794 } else {
1795 None
1796 }
1797 }) {
1798 SlotLookupResult::NativeSlot(func) => {
1799 self.slots.as_buffer.store(Some(func));
1800 }
1801 SlotLookupResult::PythonMethod => {
1802 self.slots.as_buffer.store(Some(python_as_buffer));
1803 }
1804 SlotLookupResult::NotFound => {
1805 accessor.inherit_from_mro(self);
1806 }
1807 }
1808 } else {
1809 accessor.inherit_from_mro(self);
1810 }
1811 }
1812 SlotAccessor::BfReleaseBuffer => {
1813 if ADD {
1816 match self.lookup_slot_in_mro(name, ctx, |sf| {
1817 if matches!(sf, SlotFunc::ReleaseBuffer) {
1818 Some(())
1819 } else {
1820 None
1821 }
1822 }) {
1823 SlotLookupResult::NativeSlot(()) => {
1824 self.slots.python_release_buffer.store(false);
1825 self.slots.has_release_buffer.store(true);
1826 }
1827 SlotLookupResult::PythonMethod => {
1828 self.slots.python_release_buffer.store(true);
1829 self.slots.has_release_buffer.store(true);
1830 }
1831 SlotLookupResult::NotFound => {
1832 accessor.inherit_from_mro(self);
1833 }
1834 }
1835 } else {
1836 accessor.inherit_from_mro(self);
1837 }
1838 }
1839
1840 _ => {}
1842 }
1843 }
1844
1845 fn lookup_slot_in_mro<T: Copy>(
1847 &self,
1848 name: &'static PyStrInterned,
1849 ctx: &Context,
1850 extract: impl Fn(&crate::builtins::descriptor::SlotFunc) -> Option<T>,
1851 ) -> SlotLookupResult<T> {
1852 use crate::builtins::descriptor::PyWrapper;
1853
1854 let is_subclass_of = |subclass_mro: &[PyRef<Self>], superclass: &Py<Self>| -> bool {
1856 subclass_mro.iter().any(|c| c.is(superclass))
1857 };
1858
1859 let try_extract = |attr: &PyObject, for_class_mro: &[PyRef<Self>]| -> Option<T> {
1863 if attr.class().is(ctx.types.wrapper_descriptor_type) {
1864 attr.downcast_ref::<PyWrapper>().and_then(|wrapper| {
1865 if is_subclass_of(for_class_mro, wrapper.typ) {
1867 extract(&wrapper.wrapped)
1868 } else {
1869 None
1870 }
1871 })
1872 } else {
1873 None
1874 }
1875 };
1876
1877 let mro = self.mro.read();
1878
1879 let attr_name = self.attributes.get(name);
1881 if let Some(attr) = attr_name {
1882 if let Some(func) = try_extract(&attr, &mro) {
1883 return SlotLookupResult::NativeSlot(func);
1884 }
1885 return SlotLookupResult::PythonMethod;
1886 }
1887
1888 for (i, cls) in mro[1..].iter().enumerate() {
1890 let attr_name = cls.attributes.get(name);
1891 if let Some(attr) = attr_name {
1892 if let Some(func) = try_extract(&attr, &mro[i + 1..]) {
1894 return SlotLookupResult::NativeSlot(func);
1895 }
1896 return SlotLookupResult::PythonMethod;
1897 }
1898 }
1899 SlotLookupResult::NotFound
1901 }
1902}
1903
1904#[pyclass]
1927pub trait Constructor: PyPayload + core::fmt::Debug {
1928 type Args: FromArgs;
1929
1930 const DROP_KWARGS_WHEN_INIT_OVERRIDDEN: bool = false;
1932
1933 #[inline]
1936 #[pyslot]
1937 fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1938 let args = if Self::DROP_KWARGS_WHEN_INIT_OVERRIDDEN {
1941 drop_kwargs_if_init_overridden(&cls, Self::class(&vm.ctx), args)
1942 } else {
1943 args
1944 };
1945 let args: Self::Args = args.bind_for(vm, Callee::of::<Self>(vm))?;
1946 let payload = Self::py_new(&cls, args, vm)?;
1947 payload.into_ref_with_type(vm, cls).map(Into::into)
1948 }
1949
1950 fn py_new(cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self>;
1953}
1954
1955pub(crate) fn drop_kwargs_if_init_overridden(
1957 cls: &Py<PyType>,
1958 base: &Py<PyType>,
1959 mut args: FuncArgs,
1960) -> FuncArgs {
1961 if args.kwargs.is_empty() {
1962 return args;
1963 }
1964 let uses_base_init = cls.slots.init.load().map(fn_addr) == base.slots.init.load().map(fn_addr);
1965 if !(cls.is(base) || uses_base_init) {
1966 args.kwargs = Default::default();
1967 }
1968 args
1969}
1970
1971pub trait DefaultConstructor: PyPayload + Default + core::fmt::Debug {
1972 fn construct_and_init(args: Self::Args, vm: &VirtualMachine) -> PyResult<PyRef<Self>>
1973 where
1974 Self: Initializer,
1975 {
1976 let this = Self::default().into_ref(&vm.ctx);
1977 Self::init(&this, args, vm)?;
1978 Ok(this)
1979 }
1980}
1981
1982impl<T> Constructor for T
1983where
1984 T: DefaultConstructor,
1985{
1986 type Args = FuncArgs;
1987
1988 fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1989 Self::default().into_ref_with_type(vm, cls).map(Into::into)
1990 }
1991
1992 fn py_new(cls: &Py<PyType>, _args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
1993 Err(vm.new_type_error(format!("cannot create {} instances", cls.slot_name())))
1994 }
1995}
1996
1997#[pyclass]
1998pub trait Initializer: PyPayload {
1999 type Args: FromArgs;
2000
2001 #[inline]
2002 #[pyslot]
2003 fn slot_init(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
2004 #[cfg(debug_assertions)]
2005 let class_name_for_debug = zelf.class().name().to_string();
2006
2007 let zelf = match zelf.try_to_ref::<Self>(vm) {
2008 Ok(zelf) => zelf,
2009 Err(err) => {
2010 #[cfg(debug_assertions)]
2011 {
2012 if let Ok(msg) = err.as_object().repr(vm) {
2013 let double_appearance = msg
2014 .to_string_lossy()
2015 .matches(&class_name_for_debug as &str)
2016 .count()
2017 == 2;
2018 assert!(
2019 !double_appearance,
2020 "This type `{class_name_for_debug}` doesn't seem to support `init`. Override `slot_init` instead: {msg}"
2021 )
2022 }
2023 }
2024 return Err(err);
2025 }
2026 };
2027 let args: Self::Args = args.bind_for(vm, Callee::of::<Self>(vm))?;
2028 Self::init(zelf, args, vm)
2029 }
2030
2031 fn init(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()>;
2032}
2033
2034#[pyclass]
2035pub trait Destructor: PyPayload {
2036 #[inline] #[pyslot]
2038 fn slot_del(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
2039 let zelf = zelf
2040 .downcast_ref()
2041 .ok_or_else(|| vm.new_type_error("unexpected payload for __del__"))?;
2042 Self::del(zelf, vm)
2043 }
2044
2045 fn del(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<()>;
2046}
2047
2048#[pyclass]
2049pub trait Callable: PyPayload {
2050 type Args: FromArgs;
2051
2052 #[inline]
2053 #[pyslot]
2054 fn slot_call(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
2055 let zelf = zelf.downcast_ref().ok_or_else(|| {
2056 let repr = zelf.repr(vm);
2057 let help: Wtf8Buf = if let Ok(repr) = repr.as_ref() {
2058 repr.as_wtf8().to_owned()
2059 } else {
2060 zelf.class().name().to_owned().into()
2061 };
2062 let mut msg = Wtf8Buf::from("unexpected payload for __call__ of ");
2063 msg.push_wtf8(&help);
2064 vm.new_type_error(msg)
2065 })?;
2066 let args = args.bind_for(vm, Callee::of::<Self>(vm))?;
2067 Self::call(zelf, args, vm)
2068 }
2069
2070 fn call(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult;
2071}
2072
2073#[pyclass]
2074pub trait GetDescriptor: PyPayload {
2075 #[pyslot]
2076 fn descr_get(
2077 zelf: &PyObject,
2078 obj: Option<&PyObject>,
2079 cls: Option<&PyObject>,
2080 vm: &VirtualMachine,
2081 ) -> PyResult;
2082
2083 #[inline]
2084 fn _as_pyref<'a>(zelf: &'a PyObject, vm: &VirtualMachine) -> PyResult<&'a Py<Self>> {
2085 zelf.try_to_value(vm)
2086 }
2087
2088 #[inline]
2089 fn _unwrap<'a, 'b>(
2090 zelf: &'a PyObject,
2091 obj: Option<&'b PyObject>,
2092 vm: &'b VirtualMachine,
2093 ) -> PyResult<(&'a Py<Self>, &'b PyObject)> {
2094 let zelf = Self::_as_pyref(zelf, vm)?;
2095 let obj = obj.unwrap_or_else(|| vm.ctx.none.as_object());
2096 Ok((zelf, obj))
2097 }
2098
2099 #[inline]
2100 fn _check<'a, 'b>(
2101 zelf: &'a PyObject,
2102 obj: Option<&'b PyObject>,
2103 vm: &VirtualMachine,
2104 ) -> Option<(&'a Py<Self>, &'b PyObject)> {
2105 let obj = obj?;
2107 Some((Self::_as_pyref(zelf, vm).unwrap(), obj))
2118 }
2119
2120 #[inline]
2121 fn _cls_is(cls: &Option<&PyObject>, other: &impl Borrow<PyObject>) -> bool {
2122 cls.is_some_and(|cls| other.borrow().is(cls))
2123 }
2124}
2125
2126#[pyclass]
2127pub trait Hashable: PyPayload {
2128 #[inline]
2129 #[pyslot]
2130 fn slot_hash(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
2131 let zelf = zelf
2132 .downcast_ref()
2133 .ok_or_else(|| vm.new_type_error("unexpected payload for __hash__"))?;
2134 Self::hash(zelf, vm)
2135 }
2136
2137 fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyHash>;
2138}
2139
2140#[pyclass]
2141pub trait Representable: PyPayload {
2142 #[inline]
2143 #[pyslot]
2144 fn slot_repr(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
2145 let zelf = zelf
2146 .downcast_ref()
2147 .ok_or_else(|| vm.new_type_error("unexpected payload for __repr__"))?;
2148 Self::repr(zelf, vm)
2149 }
2150
2151 #[inline]
2152 fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
2153 let repr = Self::repr_wtf8(zelf, vm)?;
2154 Ok(vm.ctx.new_str(repr))
2155 }
2156
2157 fn repr_wtf8(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
2158 Self::repr_str(zelf, vm).map(|utf8| utf8.into())
2159 }
2160 fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
2161 unreachable!("Representable requires overriding either repr_str or repr_wtf8")
2162 }
2163}
2164
2165#[pyclass]
2166pub trait Comparable: PyPayload {
2167 #[inline]
2168 #[pyslot]
2169 fn slot_richcompare(
2170 zelf: &PyObject,
2171 other: &PyObject,
2172 op: PyComparisonOp,
2173 vm: &VirtualMachine,
2174 ) -> PyResult<Either<PyObjectRef, PyComparisonValue>> {
2175 let zelf = zelf.downcast_ref().ok_or_else(|| {
2176 vm.new_type_error(format!(
2177 "unexpected payload for {}",
2178 op.method_name(&vm.ctx).as_str()
2179 ))
2180 })?;
2181 Self::cmp(zelf, other, op, vm).map(Either::B)
2182 }
2183
2184 fn cmp(
2185 zelf: &Py<Self>,
2186 other: &PyObject,
2187 op: PyComparisonOp,
2188 vm: &VirtualMachine,
2189 ) -> PyResult<PyComparisonValue>;
2190}
2191
2192#[derive(Debug, Copy, Clone, Eq, PartialEq)]
2193#[repr(transparent)]
2194pub struct PyComparisonOp(ComparisonOperator);
2195
2196impl From<ComparisonOperator> for PyComparisonOp {
2197 fn from(op: ComparisonOperator) -> Self {
2198 Self(op)
2199 }
2200}
2201
2202#[allow(non_upper_case_globals)]
2203impl PyComparisonOp {
2204 pub const Lt: Self = Self(ComparisonOperator::Less);
2205 pub const Gt: Self = Self(ComparisonOperator::Greater);
2206 pub const Ne: Self = Self(ComparisonOperator::NotEqual);
2207 pub const Eq: Self = Self(ComparisonOperator::Equal);
2208 pub const Le: Self = Self(ComparisonOperator::LessOrEqual);
2209 pub const Ge: Self = Self(ComparisonOperator::GreaterOrEqual);
2210}
2211
2212impl PyComparisonOp {
2213 pub fn eq_only(
2214 self,
2215 f: impl FnOnce() -> PyResult<PyComparisonValue>,
2216 ) -> PyResult<PyComparisonValue> {
2217 match self {
2218 Self::Eq => f(),
2219 Self::Ne => f().map(|x| x.map(|eq| !eq)),
2220 _ => Ok(PyComparisonValue::NotImplemented),
2221 }
2222 }
2223
2224 #[must_use]
2225 pub fn eval_ord(self, ord: Ordering) -> bool {
2226 match self {
2227 Self::Lt => ord == Ordering::Less,
2228 Self::Le => ord != Ordering::Greater,
2229 Self::Eq => ord == Ordering::Equal,
2230 Self::Ne => ord != Ordering::Equal,
2231 Self::Gt => ord == Ordering::Greater,
2232 Self::Ge => ord != Ordering::Less,
2233 }
2234 }
2235
2236 #[must_use]
2237 pub const fn swapped(self) -> Self {
2238 match self {
2239 Self::Lt => Self::Gt,
2240 Self::Le => Self::Ge,
2241 Self::Eq => Self::Eq,
2242 Self::Ne => Self::Ne,
2243 Self::Ge => Self::Le,
2244 Self::Gt => Self::Lt,
2245 }
2246 }
2247
2248 pub fn method_name(self, ctx: &Context) -> &'static PyStrInterned {
2249 match self {
2250 Self::Lt => identifier!(ctx, __lt__),
2251 Self::Le => identifier!(ctx, __le__),
2252 Self::Eq => identifier!(ctx, __eq__),
2253 Self::Ne => identifier!(ctx, __ne__),
2254 Self::Ge => identifier!(ctx, __ge__),
2255 Self::Gt => identifier!(ctx, __gt__),
2256 }
2257 }
2258
2259 #[must_use]
2260 pub const fn operator_token(self) -> &'static str {
2261 match self {
2262 Self::Lt => "<",
2263 Self::Le => "<=",
2264 Self::Eq => "==",
2265 Self::Ne => "!=",
2266 Self::Ge => ">=",
2267 Self::Gt => ">",
2268 }
2269 }
2270
2271 #[inline]
2274 pub fn identical_optimization(
2275 self,
2276 a: &impl Borrow<PyObject>,
2277 b: &impl Borrow<PyObject>,
2278 ) -> Option<bool> {
2279 self.map_eq(|| a.borrow().is(b.borrow()))
2280 }
2281
2282 #[inline]
2297 pub fn eval_eq(self, equal: impl FnOnce() -> bool) -> Option<bool> {
2298 match self {
2299 Self::Eq => Some(equal()),
2300 Self::Ne => Some(!equal()),
2301 _ => None,
2302 }
2303 }
2304
2305 #[inline]
2308 pub fn map_eq(self, f: impl FnOnce() -> bool) -> Option<bool> {
2309 let eq = match self {
2310 Self::Eq => true,
2311 Self::Ne => false,
2312 _ => return None,
2313 };
2314 f().then_some(eq)
2315 }
2316}
2317
2318#[pyclass]
2319pub trait GetAttr: PyPayload {
2320 #[pyslot]
2321 fn slot_getattro(obj: &PyObject, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
2322 let zelf = obj
2323 .downcast_ref()
2324 .ok_or_else(|| vm.new_type_error("unexpected payload for __getattribute__"))?;
2325 Self::getattro(zelf, name, vm)
2326 }
2327
2328 fn getattro(zelf: &Py<Self>, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult;
2329}
2330
2331#[pyclass]
2332pub trait SetAttr: PyPayload {
2333 #[pyslot]
2334 #[inline]
2335 fn slot_setattro(
2336 obj: &PyObject,
2337 name: &Py<PyStr>,
2338 value: PySetterValue,
2339 vm: &VirtualMachine,
2340 ) -> PyResult<()> {
2341 let zelf = obj
2342 .downcast_ref::<Self>()
2343 .ok_or_else(|| vm.new_type_error("unexpected payload for __setattr__"))?;
2344 Self::setattro(zelf, name, value, vm)
2345 }
2346
2347 fn setattro(
2348 zelf: &Py<Self>,
2349 name: &Py<PyStr>,
2350 value: PySetterValue,
2351 vm: &VirtualMachine,
2352 ) -> PyResult<()>;
2353}
2354
2355#[pyclass]
2356pub trait AsBuffer: PyPayload {
2357 const RELEASE_BUFFER: bool = false;
2360
2361 #[inline]
2362 #[pyslot]
2363 fn slot_as_buffer(
2364 zelf: &PyObject,
2365 flags: BufferFlags,
2366 vm: &VirtualMachine,
2367 ) -> PyResult<PyBuffer> {
2368 let zelf = zelf
2369 .downcast_ref()
2370 .ok_or_else(|| vm.new_type_error("unexpected payload for as_buffer"))?;
2371 let buffer = Self::as_buffer(zelf, vm)?;
2372 if let Err(exc) = flags.check_writable(buffer.desc.readonly, "Object is not writable.", vm)
2373 {
2374 buffer.abort_acquisition();
2377 return Err(exc);
2378 }
2379 Ok(buffer)
2380 }
2381
2382 fn as_buffer(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyBuffer>;
2383}
2384
2385#[pyclass]
2386pub trait AsMapping: PyPayload {
2387 fn as_mapping() -> &'static PyMappingMethods;
2388
2389 #[inline]
2390 #[must_use]
2391 fn mapping_downcast(mapping: PyMapping<'_>) -> &Py<Self> {
2392 unsafe { mapping.obj.downcast_unchecked_ref() }
2393 }
2394
2395 fn extend_slots(slots: &mut PyTypeSlots) {
2396 slots.as_mapping.copy_from(Self::as_mapping());
2397 }
2398}
2399
2400#[pyclass]
2401pub trait AsSequence: PyPayload {
2402 fn as_sequence() -> &'static PySequenceMethods;
2403
2404 #[inline]
2405 #[must_use]
2406 fn sequence_downcast(seq: PySequence<'_>) -> &Py<Self> {
2407 unsafe { seq.obj.downcast_unchecked_ref() }
2408 }
2409
2410 fn extend_slots(slots: &mut PyTypeSlots) {
2411 slots.as_sequence.copy_from(Self::as_sequence());
2412 }
2413}
2414
2415#[pyclass]
2416pub trait AsNumber: PyPayload {
2417 #[pyslot]
2418 fn as_number() -> &'static PyNumberMethods;
2419
2420 fn extend_slots(slots: &mut PyTypeSlots) {
2421 slots.as_number.copy_from(Self::as_number());
2422 }
2423
2424 fn clone_exact(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
2425 unimplemented!()
2427 }
2428
2429 #[inline]
2430 #[must_use]
2431 fn number_downcast(num: PyNumber<'_>) -> &Py<Self> {
2432 unsafe { num.obj.downcast_unchecked_ref() }
2433 }
2434
2435 #[inline]
2436 fn number_downcast_exact(num: PyNumber<'_>, vm: &VirtualMachine) -> PyRef<Self> {
2437 if let Some(zelf) = num.downcast_ref_if_exact::<Self>(vm) {
2438 zelf.to_owned()
2439 } else {
2440 Self::clone_exact(Self::number_downcast(num), vm)
2441 }
2442 }
2443}
2444
2445#[pyclass]
2446pub trait Iterable: PyPayload {
2447 #[pyslot]
2448 fn slot_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2449 let zelf = zelf
2450 .downcast()
2451 .map_err(|_| vm.new_type_error("unexpected payload for __iter__"))?;
2452 Self::iter(zelf, vm)
2453 }
2454
2455 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult;
2456
2457 fn extend_slots(_slots: &mut PyTypeSlots) {}
2458}
2459
2460#[pyclass(with(Iterable))]
2462pub trait IterNext: PyPayload + Iterable {
2463 #[pyslot]
2464 fn slot_iternext(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
2465 let zelf = zelf
2466 .downcast_ref()
2467 .ok_or_else(|| vm.new_type_error("unexpected payload for __next__"))?;
2468 Self::next(zelf, vm)
2469 }
2470
2471 fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn>;
2472}
2473
2474pub trait SelfIter: PyPayload {}
2475
2476impl<T> Iterable for T
2477where
2478 T: SelfIter,
2479{
2480 #[cold]
2481 fn slot_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
2482 let repr = zelf.repr(vm)?;
2483 unreachable!("slot must be overridden for {}", repr.as_wtf8());
2484 }
2485
2486 #[cold]
2487 fn iter(_zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult {
2488 unreachable!("slot_iter is implemented");
2489 }
2490
2491 fn extend_slots(slots: &mut PyTypeSlots) {
2492 let prev = slots.iter.swap(Some(self_iter));
2493 debug_assert!(prev.is_some()); }
2495}
2496
2497#[inline(always)]
2510pub(crate) fn fn_addr<T: Copy>(f: T) -> usize {
2511 assert!(
2512 core::mem::size_of::<T>() == core::mem::size_of::<usize>(),
2513 "fn_addr: T must be pointer-sized"
2514 );
2515 unsafe { core::mem::transmute_copy::<T, usize>(&f) }
2516}