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