1use core::ops::Deref;
2
3use crossbeam_utils::atomic::AtomicCell;
4
5use crate::{
6 AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject,
7 VirtualMachine,
8 builtins::{
9 PyBaseExceptionRef, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr, int,
10 },
11 common::int::{BytesToIntError, bytes_to_int},
12 function::ArgBytesLike,
13 object::{Traverse, TraverseFn},
14 stdlib::_warnings,
15};
16
17pub type PyNumberUnaryFunc<R = PyObjectRef> = fn(PyNumber<'_>, &VirtualMachine) -> PyResult<R>;
18pub type PyNumberBinaryFunc = fn(&PyObject, &PyObject, &VirtualMachine) -> PyResult;
19pub type PyNumberTernaryFunc = fn(&PyObject, &PyObject, &PyObject, &VirtualMachine) -> PyResult;
20
21impl PyObject {
22 #[inline]
23 pub const fn number(&self) -> PyNumber<'_> {
24 PyNumber { obj: self }
25 }
26
27 pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
28 if let Some(i) = self.downcast_ref_if_exact::<PyInt>(vm) {
29 Some(Ok(i.to_owned()))
30 } else if let Some(i) = self.downcast_ref::<PyInt>() {
31 Some(Ok(vm.ctx.new_bigint(i.as_bigint())))
32 } else {
33 self.number().index(vm)
34 }
35 }
36
37 #[inline]
38 pub fn try_index(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
39 self.try_index_opt(vm).transpose()?.ok_or_else(|| {
40 vm.new_type_error(format!(
41 "'{}' object cannot be interpreted as an integer",
42 self.class()
43 ))
44 })
45 }
46
47 pub fn try_int(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
48 fn try_convert(obj: &PyObject, lit: &[u8], vm: &VirtualMachine) -> PyResult<PyIntRef> {
49 let base = 10;
50 let digit_limit = vm.state.int_max_str_digits.load();
51
52 let i = bytes_to_int(lit, base, digit_limit)
53 .map_err(|e| handle_bytes_to_int_err(e, obj, vm))?;
54 Ok(PyInt::from(i).into_ref(&vm.ctx))
55 }
56
57 if let Some(i) = self.downcast_ref_if_exact::<PyInt>(vm) {
58 Ok(i.to_owned())
59 } else if let Some(i) = self.number().int(vm).or_else(|| self.try_index_opt(vm)) {
60 i
61 } else if let Ok(Some(f)) = vm.get_special_method(self, identifier!(vm, __trunc__)) {
62 _warnings::warn(
63 vm.ctx.exceptions.deprecation_warning,
64 "The delegation of int() to __trunc__ is deprecated.".to_owned(),
65 1,
66 vm,
67 )?;
68 let ret = f.invoke((), vm)?;
69 ret.try_index(vm).map_err(|_| {
70 vm.new_type_error(format!(
71 "__trunc__ returned non-Integral (type {})",
72 ret.class()
73 ))
74 })
75 } else if let Some(s) = self.downcast_ref::<PyStr>() {
76 try_convert(self, s.as_wtf8().trim().as_bytes(), vm)
77 } else if let Some(bytes) = self.downcast_ref::<PyBytes>() {
78 try_convert(self, bytes, vm)
79 } else if let Some(bytearray) = self.downcast_ref::<PyByteArray>() {
80 try_convert(self, &bytearray.borrow_buf(), vm)
81 } else if let Ok(buffer) = ArgBytesLike::try_from_borrowed_object(vm, self) {
82 try_convert(self, &buffer.borrow_buf(), vm)
84 } else {
85 Err(vm.new_type_error(format!(
86 "int() argument must be a string, a bytes-like object or a real number, not '{}'",
87 self.class()
88 )))
89 }
90 }
91
92 pub fn try_float_opt(&self, vm: &VirtualMachine) -> Option<PyResult<PyRef<PyFloat>>> {
93 if let Some(float) = self.downcast_ref_if_exact::<PyFloat>(vm) {
94 Some(Ok(float.to_owned()))
95 } else if let Some(f) = self.number().float(vm) {
96 Some(f)
97 } else {
98 self.try_index_opt(vm)
99 .map(|i| Ok(vm.ctx.new_float(int::try_to_float(i?.as_bigint(), vm)?)))
100 }
101 }
102
103 #[inline]
104 pub fn try_float(&self, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
105 self.try_float_opt(vm).ok_or_else(|| {
106 vm.new_type_error(format!("must be real number, not {}", self.class()))
107 })?
108 }
109}
110
111#[derive(Default)]
112pub struct PyNumberMethods {
113 pub add: Option<PyNumberBinaryFunc>,
117 pub subtract: Option<PyNumberBinaryFunc>,
118 pub multiply: Option<PyNumberBinaryFunc>,
119 pub remainder: Option<PyNumberBinaryFunc>,
120 pub divmod: Option<PyNumberBinaryFunc>,
121 pub power: Option<PyNumberTernaryFunc>,
122 pub negative: Option<PyNumberUnaryFunc>,
123 pub positive: Option<PyNumberUnaryFunc>,
124 pub absolute: Option<PyNumberUnaryFunc>,
125 pub boolean: Option<PyNumberUnaryFunc<bool>>,
126 pub invert: Option<PyNumberUnaryFunc>,
127 pub lshift: Option<PyNumberBinaryFunc>,
128 pub rshift: Option<PyNumberBinaryFunc>,
129 pub and: Option<PyNumberBinaryFunc>,
130 pub xor: Option<PyNumberBinaryFunc>,
131 pub or: Option<PyNumberBinaryFunc>,
132 pub int: Option<PyNumberUnaryFunc>,
133 pub float: Option<PyNumberUnaryFunc>,
134
135 pub inplace_add: Option<PyNumberBinaryFunc>,
136 pub inplace_subtract: Option<PyNumberBinaryFunc>,
137 pub inplace_multiply: Option<PyNumberBinaryFunc>,
138 pub inplace_remainder: Option<PyNumberBinaryFunc>,
139 pub inplace_power: Option<PyNumberTernaryFunc>,
140 pub inplace_lshift: Option<PyNumberBinaryFunc>,
141 pub inplace_rshift: Option<PyNumberBinaryFunc>,
142 pub inplace_and: Option<PyNumberBinaryFunc>,
143 pub inplace_xor: Option<PyNumberBinaryFunc>,
144 pub inplace_or: Option<PyNumberBinaryFunc>,
145
146 pub floor_divide: Option<PyNumberBinaryFunc>,
147 pub true_divide: Option<PyNumberBinaryFunc>,
148 pub inplace_floor_divide: Option<PyNumberBinaryFunc>,
149 pub inplace_true_divide: Option<PyNumberBinaryFunc>,
150
151 pub index: Option<PyNumberUnaryFunc>,
152
153 pub matrix_multiply: Option<PyNumberBinaryFunc>,
154 pub inplace_matrix_multiply: Option<PyNumberBinaryFunc>,
155}
156
157impl PyNumberMethods {
158 pub const NOT_IMPLEMENTED: Self = Self {
160 add: None,
161 subtract: None,
162 multiply: None,
163 remainder: None,
164 divmod: None,
165 power: None,
166 negative: None,
167 positive: None,
168 absolute: None,
169 boolean: None,
170 invert: None,
171 lshift: None,
172 rshift: None,
173 and: None,
174 xor: None,
175 or: None,
176 int: None,
177 float: None,
178 inplace_add: None,
179 inplace_subtract: None,
180 inplace_multiply: None,
181 inplace_remainder: None,
182 inplace_power: None,
183 inplace_lshift: None,
184 inplace_rshift: None,
185 inplace_and: None,
186 inplace_xor: None,
187 inplace_or: None,
188 floor_divide: None,
189 true_divide: None,
190 inplace_floor_divide: None,
191 inplace_true_divide: None,
192 index: None,
193 matrix_multiply: None,
194 inplace_matrix_multiply: None,
195 };
196
197 pub fn not_implemented() -> &'static Self {
198 static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED;
199 &GLOBAL_NOT_IMPLEMENTED
200 }
201}
202
203#[derive(Copy, Clone)]
205pub enum PyNumberBinaryOp {
206 Add,
207 And,
208 FloorDivide,
209 Lshift,
210 MatrixMultiply,
211 Multiply,
212 Remainder,
213 Or,
214 Rshift,
215 Subtract,
216 TrueDivide,
217 Xor,
218 InplaceAdd,
219 InplaceAnd,
220 InplaceFloorDivide,
221 InplaceLshift,
222 InplaceMatrixMultiply,
223 InplaceMultiply,
224 InplaceRemainder,
225 InplaceOr,
226 InplaceRshift,
227 InplaceSubtract,
228 InplaceTrueDivide,
229 InplaceXor,
230 Divmod,
231}
232
233impl PyNumberBinaryOp {
234 pub fn right_method_name(
236 self,
237 vm: &VirtualMachine,
238 ) -> Option<&'static crate::builtins::PyStrInterned> {
239 use PyNumberBinaryOp::*;
240 Some(match self {
241 Add => identifier!(vm, __radd__),
242 Subtract => identifier!(vm, __rsub__),
243 Multiply => identifier!(vm, __rmul__),
244 Remainder => identifier!(vm, __rmod__),
245 Divmod => identifier!(vm, __rdivmod__),
246 Lshift => identifier!(vm, __rlshift__),
247 Rshift => identifier!(vm, __rrshift__),
248 And => identifier!(vm, __rand__),
249 Xor => identifier!(vm, __rxor__),
250 Or => identifier!(vm, __ror__),
251 FloorDivide => identifier!(vm, __rfloordiv__),
252 TrueDivide => identifier!(vm, __rtruediv__),
253 MatrixMultiply => identifier!(vm, __rmatmul__),
254 InplaceAdd
256 | InplaceSubtract
257 | InplaceMultiply
258 | InplaceRemainder
259 | InplaceLshift
260 | InplaceRshift
261 | InplaceAnd
262 | InplaceXor
263 | InplaceOr
264 | InplaceFloorDivide
265 | InplaceTrueDivide
266 | InplaceMatrixMultiply => return None,
267 })
268 }
269}
270
271#[derive(Copy, Clone)]
272pub enum PyNumberTernaryOp {
273 Power,
274 InplacePower,
275}
276
277impl PyNumberTernaryOp {
278 pub fn right_method_name(
280 self,
281 vm: &VirtualMachine,
282 ) -> Option<&'static crate::builtins::PyStrInterned> {
283 Some(match self {
284 PyNumberTernaryOp::Power => identifier!(vm, __rpow__),
285 PyNumberTernaryOp::InplacePower => return None,
286 })
287 }
288}
289
290#[derive(Default)]
291pub struct PyNumberSlots {
292 pub add: AtomicCell<Option<PyNumberBinaryFunc>>,
293 pub subtract: AtomicCell<Option<PyNumberBinaryFunc>>,
294 pub multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
295 pub remainder: AtomicCell<Option<PyNumberBinaryFunc>>,
296 pub divmod: AtomicCell<Option<PyNumberBinaryFunc>>,
297 pub power: AtomicCell<Option<PyNumberTernaryFunc>>,
298 pub negative: AtomicCell<Option<PyNumberUnaryFunc>>,
299 pub positive: AtomicCell<Option<PyNumberUnaryFunc>>,
300 pub absolute: AtomicCell<Option<PyNumberUnaryFunc>>,
301 pub boolean: AtomicCell<Option<PyNumberUnaryFunc<bool>>>,
302 pub invert: AtomicCell<Option<PyNumberUnaryFunc>>,
303 pub lshift: AtomicCell<Option<PyNumberBinaryFunc>>,
304 pub rshift: AtomicCell<Option<PyNumberBinaryFunc>>,
305 pub and: AtomicCell<Option<PyNumberBinaryFunc>>,
306 pub xor: AtomicCell<Option<PyNumberBinaryFunc>>,
307 pub or: AtomicCell<Option<PyNumberBinaryFunc>>,
308 pub int: AtomicCell<Option<PyNumberUnaryFunc>>,
309 pub float: AtomicCell<Option<PyNumberUnaryFunc>>,
310
311 pub right_add: AtomicCell<Option<PyNumberBinaryFunc>>,
313 pub right_subtract: AtomicCell<Option<PyNumberBinaryFunc>>,
314 pub right_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
315 pub right_remainder: AtomicCell<Option<PyNumberBinaryFunc>>,
316 pub right_divmod: AtomicCell<Option<PyNumberBinaryFunc>>,
317 pub right_power: AtomicCell<Option<PyNumberTernaryFunc>>,
318 pub right_lshift: AtomicCell<Option<PyNumberBinaryFunc>>,
319 pub right_rshift: AtomicCell<Option<PyNumberBinaryFunc>>,
320 pub right_and: AtomicCell<Option<PyNumberBinaryFunc>>,
321 pub right_xor: AtomicCell<Option<PyNumberBinaryFunc>>,
322 pub right_or: AtomicCell<Option<PyNumberBinaryFunc>>,
323
324 pub inplace_add: AtomicCell<Option<PyNumberBinaryFunc>>,
325 pub inplace_subtract: AtomicCell<Option<PyNumberBinaryFunc>>,
326 pub inplace_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
327 pub inplace_remainder: AtomicCell<Option<PyNumberBinaryFunc>>,
328 pub inplace_power: AtomicCell<Option<PyNumberTernaryFunc>>,
329 pub inplace_lshift: AtomicCell<Option<PyNumberBinaryFunc>>,
330 pub inplace_rshift: AtomicCell<Option<PyNumberBinaryFunc>>,
331 pub inplace_and: AtomicCell<Option<PyNumberBinaryFunc>>,
332 pub inplace_xor: AtomicCell<Option<PyNumberBinaryFunc>>,
333 pub inplace_or: AtomicCell<Option<PyNumberBinaryFunc>>,
334
335 pub floor_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
336 pub true_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
337 pub right_floor_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
338 pub right_true_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
339 pub inplace_floor_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
340 pub inplace_true_divide: AtomicCell<Option<PyNumberBinaryFunc>>,
341
342 pub index: AtomicCell<Option<PyNumberUnaryFunc>>,
343
344 pub matrix_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
345 pub right_matrix_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
346 pub inplace_matrix_multiply: AtomicCell<Option<PyNumberBinaryFunc>>,
347}
348
349impl From<&PyNumberMethods> for PyNumberSlots {
350 fn from(value: &PyNumberMethods) -> Self {
351 Self {
353 add: AtomicCell::new(value.add),
354 subtract: AtomicCell::new(value.subtract),
355 multiply: AtomicCell::new(value.multiply),
356 remainder: AtomicCell::new(value.remainder),
357 divmod: AtomicCell::new(value.divmod),
358 power: AtomicCell::new(value.power),
359 negative: AtomicCell::new(value.negative),
360 positive: AtomicCell::new(value.positive),
361 absolute: AtomicCell::new(value.absolute),
362 boolean: AtomicCell::new(value.boolean),
363 invert: AtomicCell::new(value.invert),
364 lshift: AtomicCell::new(value.lshift),
365 rshift: AtomicCell::new(value.rshift),
366 and: AtomicCell::new(value.and),
367 xor: AtomicCell::new(value.xor),
368 or: AtomicCell::new(value.or),
369 int: AtomicCell::new(value.int),
370 float: AtomicCell::new(value.float),
371 right_add: AtomicCell::new(value.add),
372 right_subtract: AtomicCell::new(value.subtract),
373 right_multiply: AtomicCell::new(value.multiply),
374 right_remainder: AtomicCell::new(value.remainder),
375 right_divmod: AtomicCell::new(value.divmod),
376 right_power: AtomicCell::new(value.power),
377 right_lshift: AtomicCell::new(value.lshift),
378 right_rshift: AtomicCell::new(value.rshift),
379 right_and: AtomicCell::new(value.and),
380 right_xor: AtomicCell::new(value.xor),
381 right_or: AtomicCell::new(value.or),
382 inplace_add: AtomicCell::new(value.inplace_add),
383 inplace_subtract: AtomicCell::new(value.inplace_subtract),
384 inplace_multiply: AtomicCell::new(value.inplace_multiply),
385 inplace_remainder: AtomicCell::new(value.inplace_remainder),
386 inplace_power: AtomicCell::new(value.inplace_power),
387 inplace_lshift: AtomicCell::new(value.inplace_lshift),
388 inplace_rshift: AtomicCell::new(value.inplace_rshift),
389 inplace_and: AtomicCell::new(value.inplace_and),
390 inplace_xor: AtomicCell::new(value.inplace_xor),
391 inplace_or: AtomicCell::new(value.inplace_or),
392 floor_divide: AtomicCell::new(value.floor_divide),
393 true_divide: AtomicCell::new(value.true_divide),
394 right_floor_divide: AtomicCell::new(value.floor_divide),
395 right_true_divide: AtomicCell::new(value.true_divide),
396 inplace_floor_divide: AtomicCell::new(value.inplace_floor_divide),
397 inplace_true_divide: AtomicCell::new(value.inplace_true_divide),
398 index: AtomicCell::new(value.index),
399 matrix_multiply: AtomicCell::new(value.matrix_multiply),
400 right_matrix_multiply: AtomicCell::new(value.matrix_multiply),
401 inplace_matrix_multiply: AtomicCell::new(value.inplace_matrix_multiply),
402 }
403 }
404}
405
406impl PyNumberSlots {
407 pub fn copy_from(&self, methods: &PyNumberMethods) {
409 if let Some(f) = methods.add {
410 self.add.store(Some(f));
411 self.right_add.store(Some(f));
412 }
413 if let Some(f) = methods.subtract {
414 self.subtract.store(Some(f));
415 self.right_subtract.store(Some(f));
416 }
417 if let Some(f) = methods.multiply {
418 self.multiply.store(Some(f));
419 self.right_multiply.store(Some(f));
420 }
421 if let Some(f) = methods.remainder {
422 self.remainder.store(Some(f));
423 self.right_remainder.store(Some(f));
424 }
425 if let Some(f) = methods.divmod {
426 self.divmod.store(Some(f));
427 self.right_divmod.store(Some(f));
428 }
429 if let Some(f) = methods.power {
430 self.power.store(Some(f));
431 self.right_power.store(Some(f));
432 }
433 if let Some(f) = methods.negative {
434 self.negative.store(Some(f));
435 }
436 if let Some(f) = methods.positive {
437 self.positive.store(Some(f));
438 }
439 if let Some(f) = methods.absolute {
440 self.absolute.store(Some(f));
441 }
442 if let Some(f) = methods.boolean {
443 self.boolean.store(Some(f));
444 }
445 if let Some(f) = methods.invert {
446 self.invert.store(Some(f));
447 }
448 if let Some(f) = methods.lshift {
449 self.lshift.store(Some(f));
450 self.right_lshift.store(Some(f));
451 }
452 if let Some(f) = methods.rshift {
453 self.rshift.store(Some(f));
454 self.right_rshift.store(Some(f));
455 }
456 if let Some(f) = methods.and {
457 self.and.store(Some(f));
458 self.right_and.store(Some(f));
459 }
460 if let Some(f) = methods.xor {
461 self.xor.store(Some(f));
462 self.right_xor.store(Some(f));
463 }
464 if let Some(f) = methods.or {
465 self.or.store(Some(f));
466 self.right_or.store(Some(f));
467 }
468 if let Some(f) = methods.int {
469 self.int.store(Some(f));
470 }
471 if let Some(f) = methods.float {
472 self.float.store(Some(f));
473 }
474 if let Some(f) = methods.inplace_add {
475 self.inplace_add.store(Some(f));
476 }
477 if let Some(f) = methods.inplace_subtract {
478 self.inplace_subtract.store(Some(f));
479 }
480 if let Some(f) = methods.inplace_multiply {
481 self.inplace_multiply.store(Some(f));
482 }
483 if let Some(f) = methods.inplace_remainder {
484 self.inplace_remainder.store(Some(f));
485 }
486 if let Some(f) = methods.inplace_power {
487 self.inplace_power.store(Some(f));
488 }
489 if let Some(f) = methods.inplace_lshift {
490 self.inplace_lshift.store(Some(f));
491 }
492 if let Some(f) = methods.inplace_rshift {
493 self.inplace_rshift.store(Some(f));
494 }
495 if let Some(f) = methods.inplace_and {
496 self.inplace_and.store(Some(f));
497 }
498 if let Some(f) = methods.inplace_xor {
499 self.inplace_xor.store(Some(f));
500 }
501 if let Some(f) = methods.inplace_or {
502 self.inplace_or.store(Some(f));
503 }
504 if let Some(f) = methods.floor_divide {
505 self.floor_divide.store(Some(f));
506 self.right_floor_divide.store(Some(f));
507 }
508 if let Some(f) = methods.true_divide {
509 self.true_divide.store(Some(f));
510 self.right_true_divide.store(Some(f));
511 }
512 if let Some(f) = methods.inplace_floor_divide {
513 self.inplace_floor_divide.store(Some(f));
514 }
515 if let Some(f) = methods.inplace_true_divide {
516 self.inplace_true_divide.store(Some(f));
517 }
518 if let Some(f) = methods.index {
519 self.index.store(Some(f));
520 }
521 if let Some(f) = methods.matrix_multiply {
522 self.matrix_multiply.store(Some(f));
523 self.right_matrix_multiply.store(Some(f));
524 }
525 if let Some(f) = methods.inplace_matrix_multiply {
526 self.inplace_matrix_multiply.store(Some(f));
527 }
528 }
529
530 pub fn left_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option<PyNumberBinaryFunc> {
531 use PyNumberBinaryOp::*;
532 match op_slot {
533 Add => self.add.load(),
534 Subtract => self.subtract.load(),
535 Multiply => self.multiply.load(),
536 Remainder => self.remainder.load(),
537 Divmod => self.divmod.load(),
538 Lshift => self.lshift.load(),
539 Rshift => self.rshift.load(),
540 And => self.and.load(),
541 Xor => self.xor.load(),
542 Or => self.or.load(),
543 InplaceAdd => self.inplace_add.load(),
544 InplaceSubtract => self.inplace_subtract.load(),
545 InplaceMultiply => self.inplace_multiply.load(),
546 InplaceRemainder => self.inplace_remainder.load(),
547 InplaceLshift => self.inplace_lshift.load(),
548 InplaceRshift => self.inplace_rshift.load(),
549 InplaceAnd => self.inplace_and.load(),
550 InplaceXor => self.inplace_xor.load(),
551 InplaceOr => self.inplace_or.load(),
552 FloorDivide => self.floor_divide.load(),
553 TrueDivide => self.true_divide.load(),
554 InplaceFloorDivide => self.inplace_floor_divide.load(),
555 InplaceTrueDivide => self.inplace_true_divide.load(),
556 MatrixMultiply => self.matrix_multiply.load(),
557 InplaceMatrixMultiply => self.inplace_matrix_multiply.load(),
558 }
559 }
560
561 pub fn right_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option<PyNumberBinaryFunc> {
562 use PyNumberBinaryOp::*;
563 match op_slot {
564 Add => self.right_add.load(),
565 Subtract => self.right_subtract.load(),
566 Multiply => self.right_multiply.load(),
567 Remainder => self.right_remainder.load(),
568 Divmod => self.right_divmod.load(),
569 Lshift => self.right_lshift.load(),
570 Rshift => self.right_rshift.load(),
571 And => self.right_and.load(),
572 Xor => self.right_xor.load(),
573 Or => self.right_or.load(),
574 FloorDivide => self.right_floor_divide.load(),
575 TrueDivide => self.right_true_divide.load(),
576 MatrixMultiply => self.right_matrix_multiply.load(),
577 _ => None,
578 }
579 }
580
581 pub fn left_ternary_op(&self, op_slot: PyNumberTernaryOp) -> Option<PyNumberTernaryFunc> {
582 use PyNumberTernaryOp::*;
583 match op_slot {
584 Power => self.power.load(),
585 InplacePower => self.inplace_power.load(),
586 }
587 }
588
589 pub fn right_ternary_op(&self, op_slot: PyNumberTernaryOp) -> Option<PyNumberTernaryFunc> {
590 use PyNumberTernaryOp::*;
591 match op_slot {
592 Power => self.right_power.load(),
593 _ => None,
594 }
595 }
596}
597#[derive(Copy, Clone)]
598pub struct PyNumber<'a> {
599 pub obj: &'a PyObject,
600}
601
602unsafe impl Traverse for PyNumber<'_> {
603 fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
604 self.obj.traverse(tracer_fn)
605 }
606}
607
608impl Deref for PyNumber<'_> {
609 type Target = PyObject;
610
611 fn deref(&self) -> &Self::Target {
612 self.obj
613 }
614}
615
616impl<'a> PyNumber<'a> {
617 pub fn check(obj: &PyObject) -> bool {
619 let methods = &obj.class().slots.as_number;
620 let has_number = methods.int.load().is_some()
621 || methods.index.load().is_some()
622 || methods.float.load().is_some();
623 has_number || obj.downcastable::<PyComplex>()
624 }
625}
626
627impl PyNumber<'_> {
628 pub fn is_index(self) -> bool {
630 self.class().slots.as_number.index.load().is_some()
631 }
632
633 #[inline]
634 pub fn int(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
635 self.class().slots.as_number.int.load().map(|f| {
636 let ret = f(self, vm)?;
637
638 if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
639 return Ok(ret.to_owned());
640 }
641
642 let ret_class = ret.class().to_owned();
643 if let Some(ret) = ret.downcast_ref::<PyInt>() {
644 _warnings::warn(
645 vm.ctx.exceptions.deprecation_warning,
646 format!(
647 "__int__ returned non-int (type {ret_class}). \
648 The ability to return an instance of a strict subclass of int \
649 is deprecated, and may be removed in a future version of Python."
650 ),
651 1,
652 vm,
653 )?;
654
655 Ok(ret.to_owned())
656 } else {
657 Err(vm.new_type_error(format!(
658 "{}.__int__ returned non-int(type {})",
659 self.class(),
660 ret_class
661 )))
662 }
663 })
664 }
665
666 #[inline]
667 pub fn index(self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
668 self.class().slots.as_number.index.load().map(|f| {
669 let ret = f(self, vm)?;
670
671 if let Some(ret) = ret.downcast_ref_if_exact::<PyInt>(vm) {
672 return Ok(ret.to_owned());
673 }
674
675 let ret_class = ret.class().to_owned();
676 if let Some(ret) = ret.downcast_ref::<PyInt>() {
677 _warnings::warn(
678 vm.ctx.exceptions.deprecation_warning,
679 format!(
680 "__index__ returned non-int (type {ret_class}). \
681 The ability to return an instance of a strict subclass of int \
682 is deprecated, and may be removed in a future version of Python."
683 ),
684 1,
685 vm,
686 )?;
687
688 Ok(ret.to_owned())
689 } else {
690 Err(vm.new_type_error(format!(
691 "{}.__index__ returned non-int(type {})",
692 self.class(),
693 ret_class
694 )))
695 }
696 })
697 }
698
699 #[inline]
700 pub fn float(self, vm: &VirtualMachine) -> Option<PyResult<PyRef<PyFloat>>> {
701 self.class().slots.as_number.float.load().map(|f| {
702 let ret = f(self, vm)?;
703
704 if let Some(ret) = ret.downcast_ref_if_exact::<PyFloat>(vm) {
705 return Ok(ret.to_owned());
706 }
707
708 let ret_class = ret.class().to_owned();
709 if let Some(ret) = ret.downcast_ref::<PyFloat>() {
710 _warnings::warn(
711 vm.ctx.exceptions.deprecation_warning,
712 format!(
713 "__float__ returned non-float (type {ret_class}). \
714 The ability to return an instance of a strict subclass of float \
715 is deprecated, and may be removed in a future version of Python."
716 ),
717 1,
718 vm,
719 )?;
720
721 Ok(ret.to_owned())
722 } else {
723 Err(vm.new_type_error(format!(
724 "{}.__float__ returned non-float(type {})",
725 self.class(),
726 ret_class
727 )))
728 }
729 })
730 }
731}
732
733pub fn handle_bytes_to_int_err(
734 e: BytesToIntError,
735 obj: &PyObject,
736 vm: &VirtualMachine,
737) -> PyBaseExceptionRef {
738 match e {
739 BytesToIntError::InvalidLiteral { base } => vm.new_value_error(format!(
740 "invalid literal for int() with base {base}: {}",
741 match obj.repr(vm) {
742 Ok(v) => v,
743 Err(err) => return err,
744 },
745 )),
746 BytesToIntError::InvalidBase => {
747 vm.new_value_error("int() base must be >= 2 and <= 36, or 0")
748 }
749 BytesToIntError::DigitLimit { got, limit } => vm.new_value_error(format!(
750"Exceeds the limit ({limit} digits) for integer string conversion: value has {got} digits; use sys.set_int_max_str_digits() to increase the limit"
751 )),
752 }
753}