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