1use super::{PyByteArray, PyBytes, PyStr, PyType, PyTypeRef, float};
2use crate::{
3 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, PyResult,
4 TryFromBorrowedObject, VirtualMachine,
5 builtins::PyUtf8StrRef,
6 bytes_inner::PyBytesInner,
7 class::PyClassImpl,
8 common::{
9 format::FormatSpec,
10 hash,
11 int::{bigint_to_finite_float, bytes_to_int, true_div},
12 wtf8::Wtf8Buf,
13 },
14 convert::{IntoPyException, ToPyObject, ToPyResult},
15 function::{
16 ArgByteOrder, ArgIntoBool, FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue,
17 PyComparisonValue,
18 },
19 protocol::{PyNumberMethods, handle_bytes_to_int_err},
20 types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable},
21};
22use alloc::fmt;
23use core::cell::Cell;
24use core::ops::{Neg, Not};
25use core::ptr::NonNull;
26use malachite_bigint::{BigInt, Sign};
27use num_integer::{ExtendedGcd, Integer};
28use num_traits::{One, Pow, PrimInt, Signed, ToPrimitive, Zero};
29
30#[pyclass(module = false, name = "int")]
31#[derive(Debug)]
32pub struct PyInt {
33 value: BigInt,
34}
35
36impl fmt::Display for PyInt {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 BigInt::fmt(&self.value, f)
39 }
40}
41
42pub type PyIntRef = PyRef<PyInt>;
43
44impl<T> From<T> for PyInt
45where
46 T: Into<BigInt>,
47{
48 fn from(v: T) -> Self {
49 Self { value: v.into() }
50 }
51}
52
53thread_local! {
55 static INT_FREELIST: Cell<crate::object::FreeList<PyInt>> = const { Cell::new(crate::object::FreeList::new()) };
56}
57
58impl PyPayload for PyInt {
59 const MAX_FREELIST: usize = 100;
60 const HAS_FREELIST: bool = true;
61
62 #[inline]
63 fn class(ctx: &Context) -> &'static Py<PyType> {
64 ctx.types.int_type
65 }
66
67 fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
68 vm.ctx.new_int(self.value).into()
69 }
70
71 #[inline]
72 unsafe fn freelist_push(obj: *mut PyObject) -> bool {
73 INT_FREELIST
74 .try_with(|fl| {
75 let mut list = fl.take();
76 let stored = if list.len() < Self::MAX_FREELIST {
77 list.push(obj);
78 true
79 } else {
80 false
81 };
82 fl.set(list);
83 stored
84 })
85 .unwrap_or(false)
86 }
87
88 #[inline]
89 unsafe fn freelist_pop(_payload: &Self) -> Option<NonNull<PyObject>> {
90 INT_FREELIST
91 .try_with(|fl| {
92 let mut list = fl.take();
93 let result = list.pop().map(|p| unsafe { NonNull::new_unchecked(p) });
94 fl.set(list);
95 result
96 })
97 .ok()
98 .flatten()
99 }
100}
101
102macro_rules! impl_into_pyobject_int {
103 ($($t:ty)*) => {$(
104 impl ToPyObject for $t {
105 fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
106 vm.ctx.new_int(self).into()
107 }
108 }
109 )*};
110}
111
112impl_into_pyobject_int!(isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 BigInt);
113
114macro_rules! impl_try_from_object_int {
115 ($(($t:ty, $to_prim:ident),)*) => {$(
116 impl<'a> TryFromBorrowedObject<'a> for $t {
117 fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
118 obj.try_value_with(|int: &PyInt| {
119 int.try_to_primitive(vm)
120 }, vm)
121 }
122 }
123 )*};
124}
125
126impl_try_from_object_int!(
127 (isize, to_isize),
128 (i8, to_i8),
129 (i16, to_i16),
130 (i32, to_i32),
131 (i64, to_i64),
132 (i128, to_i128),
133 (usize, to_usize),
134 (u8, to_u8),
135 (u16, to_u16),
136 (u32, to_u32),
137 (u64, to_u64),
138 (u128, to_u128),
139);
140
141fn inner_pow(int1: &BigInt, int2: &BigInt, vm: &VirtualMachine) -> PyResult {
142 if int2.is_negative() {
143 let v1 = try_to_float(int1, vm)?;
144 let v2 = try_to_float(int2, vm)?;
145 float::float_pow(v1, v2, vm)
146 } else {
147 let value = if let Some(v2) = int2.to_u64() {
148 return Ok(vm.ctx.new_int(Pow::pow(int1, v2)).into());
149 } else if int1.is_one() {
150 1
151 } else if int1.is_zero() {
152 0
153 } else if int1 == &BigInt::from(-1) {
154 if int2.is_odd() { -1 } else { 1 }
155 } else {
156 return Ok(vm.ctx.not_implemented());
159 };
160 Ok(vm.ctx.new_int(value).into())
161 }
162}
163
164fn inner_mod(int1: &BigInt, int2: &BigInt, vm: &VirtualMachine) -> PyResult {
165 if int2.is_zero() {
166 Err(vm.new_zero_division_error("division by zero"))
167 } else {
168 Ok(vm.ctx.new_int(int1.mod_floor(int2)).into())
169 }
170}
171
172fn inner_floordiv(int1: &BigInt, int2: &BigInt, vm: &VirtualMachine) -> PyResult {
173 if int2.is_zero() {
174 Err(vm.new_zero_division_error("division by zero"))
175 } else {
176 Ok(vm.ctx.new_int(int1.div_floor(int2)).into())
177 }
178}
179
180fn inner_divmod(int1: &BigInt, int2: &BigInt, vm: &VirtualMachine) -> PyResult {
181 if int2.is_zero() {
182 return Err(vm.new_zero_division_error("division by zero"));
183 }
184 let (div, modulo) = int1.div_mod_floor(int2);
185 Ok(vm.new_tuple((div, modulo)).into())
186}
187
188fn inner_lshift(base: &BigInt, bits: &BigInt, vm: &VirtualMachine) -> PyResult {
189 inner_shift(
190 base,
191 bits,
192 |base, bits| base << bits,
193 |bits, vm| {
194 bits.to_usize()
195 .ok_or_else(|| vm.new_overflow_error("the number is too large to convert to int"))
196 },
197 vm,
198 )
199}
200
201fn inner_rshift(base: &BigInt, bits: &BigInt, vm: &VirtualMachine) -> PyResult {
202 inner_shift(
203 base,
204 bits,
205 |base, bits| base >> bits,
206 |bits, _vm| Ok(bits.to_usize().unwrap_or(usize::MAX)),
207 vm,
208 )
209}
210
211fn inner_shift<F, S>(
212 base: &BigInt,
213 bits: &BigInt,
214 shift_op: F,
215 shift_bits: S,
216 vm: &VirtualMachine,
217) -> PyResult
218where
219 F: Fn(&BigInt, usize) -> BigInt,
220 S: Fn(&BigInt, &VirtualMachine) -> PyResult<usize>,
221{
222 if bits.is_negative() {
223 Err(vm.new_value_error("negative shift count"))
224 } else if base.is_zero() {
225 Ok(vm.ctx.new_int(0).into())
226 } else {
227 shift_bits(bits, vm).map(|bits| vm.ctx.new_int(shift_op(base, bits)).into())
228 }
229}
230
231fn inner_truediv(i1: &BigInt, i2: &BigInt, vm: &VirtualMachine) -> PyResult {
232 if i2.is_zero() {
233 return Err(vm.new_zero_division_error("division by zero"));
234 }
235
236 let float = true_div(i1, i2);
237
238 if float.is_infinite() {
239 Err(vm.new_exception_msg(
240 vm.ctx.exceptions.overflow_error.to_owned(),
241 "integer division result too large for a float".into(),
242 ))
243 } else {
244 Ok(vm.ctx.new_float(float).into())
245 }
246}
247
248impl Constructor for PyInt {
249 type Args = FuncArgs;
250
251 fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
252 if cls.is(vm.ctx.types.bool_type) {
253 return Err(vm.new_type_error("int.__new__(bool) is not safe, use bool.__new__()"));
254 }
255
256 if cls.is(vm.ctx.types.int_type)
258 && args.args.len() == 1
259 && args.kwargs.is_empty()
260 && args.args[0].class().is(vm.ctx.types.int_type)
261 {
262 return Ok(args.args[0].clone());
263 }
264
265 let options: IntOptions = args.bind(vm)?;
266 let value = if let OptionalArg::Present(val) = options.val_options {
267 if let OptionalArg::Present(base) = options.base {
268 let base = base
269 .try_index(vm)?
270 .as_bigint()
271 .to_u32()
272 .filter(|&v| v == 0 || (2..=36).contains(&v))
273 .ok_or_else(|| vm.new_value_error("int() base must be >= 2 and <= 36, or 0"))?;
274 try_int_radix(&val, base, vm)
275 } else {
276 val.try_int(vm).map(|x| x.as_bigint().clone())
277 }
278 } else if let OptionalArg::Present(_) = options.base {
279 Err(vm.new_type_error("int() missing string argument"))
280 } else {
281 Ok(Zero::zero())
282 }?;
283
284 Self::with_value(cls, value, vm).map(Into::into)
285 }
286
287 fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
288 unimplemented!("use slot_new")
289 }
290}
291
292impl PyInt {
293 fn with_value<T>(cls: PyTypeRef, value: T, vm: &VirtualMachine) -> PyResult<PyRef<Self>>
294 where
295 T: Into<BigInt> + ToPrimitive,
296 {
297 if cls.is(vm.ctx.types.int_type) {
298 Ok(vm.ctx.new_int(value))
299 } else if cls.is(vm.ctx.types.bool_type) {
300 Ok(vm.ctx.new_bool(!value.into().eq(&BigInt::zero())).upcast())
301 } else {
302 Self::from(value).into_ref_with_type(vm, cls)
303 }
304 }
305
306 pub const fn as_bigint(&self) -> &BigInt {
307 &self.value
308 }
309
310 #[inline]
312 pub fn to_str_radix_10(&self) -> String {
313 match self.value.to_i64() {
314 Some(i) => i.to_string(),
315 None => self.value.to_string(),
316 }
317 }
318
319 pub fn as_u32_mask(&self) -> u32 {
321 let v = self.as_bigint();
322 v.to_u32()
323 .or_else(|| v.to_i32().map(|i| i as u32))
324 .unwrap_or_else(|| {
325 let mut out = 0u32;
326 for digit in v.iter_u32_digits() {
327 out = out.wrapping_shl(32) | digit;
328 }
329 match v.sign() {
330 Sign::Minus => out * -1i32 as u32,
331 _ => out,
332 }
333 })
334 }
335
336 pub fn try_to_primitive<'a, I>(&'a self, vm: &VirtualMachine) -> PyResult<I>
337 where
338 I: PrimInt + TryFrom<&'a BigInt>,
339 {
340 I::try_from(self.as_bigint()).map_err(|_| {
348 vm.new_overflow_error(format!(
349 "Python int too large to convert to Rust {}",
350 core::any::type_name::<I>()
351 ))
352 })
353 }
354
355 #[inline]
356 fn int_op<F>(&self, other: PyObjectRef, op: F) -> PyArithmeticValue<BigInt>
357 where
358 F: Fn(&BigInt, &BigInt) -> BigInt,
359 {
360 let r = other
361 .downcast_ref::<Self>()
362 .map(|other| op(&self.value, &other.value));
363 PyArithmeticValue::from_option(r)
364 }
365
366 #[inline]
367 fn general_op<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult
368 where
369 F: Fn(&BigInt, &BigInt) -> PyResult,
370 {
371 if let Some(other) = other.downcast_ref::<Self>() {
372 op(&self.value, &other.value)
373 } else {
374 Ok(vm.ctx.not_implemented())
375 }
376 }
377}
378
379#[pyclass(
380 itemsize = 4,
381 flags(BASETYPE, _MATCH_SELF),
382 with(PyRef, Comparable, Hashable, Constructor, AsNumber, Representable)
383)]
384impl PyInt {
385 pub(crate) fn __xor__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
386 self.int_op(other, |a, b| a ^ b)
387 }
388
389 pub(crate) fn __or__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
390 self.int_op(other, |a, b| a | b)
391 }
392
393 pub(crate) fn __and__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
394 self.int_op(other, |a, b| a & b)
395 }
396
397 fn modpow(&self, other: PyObjectRef, modulus: PyObjectRef, vm: &VirtualMachine) -> PyResult {
398 let modulus = match modulus.downcast_ref::<Self>() {
399 Some(val) => val.as_bigint(),
400 None => return Ok(vm.ctx.not_implemented()),
401 };
402 if modulus.is_zero() {
403 return Err(vm.new_value_error("pow() 3rd argument cannot be 0"));
404 }
405
406 self.general_op(
407 other,
408 |a, b| {
409 let i = if b.is_negative() {
410 fn normalize(a: BigInt, n: &BigInt) -> BigInt {
413 let a = a % n;
414 if a.is_negative() { a + n } else { a }
415 }
416 fn inverse(a: BigInt, n: &BigInt) -> Option<BigInt> {
417 let ExtendedGcd { gcd, x: c, .. } = a.extended_gcd(n);
418 if gcd.is_one() {
419 Some(normalize(c, n))
420 } else {
421 None
422 }
423 }
424 let a = inverse(a % modulus, modulus).ok_or_else(|| {
425 vm.new_value_error("base is not invertible for the given modulus")
426 })?;
427 let b = -b;
428 a.modpow(&b, modulus)
429 } else {
430 a.modpow(b, modulus)
431 };
432 Ok(vm.ctx.new_int(i).into())
433 },
434 vm,
435 )
436 }
437
438 #[pymethod]
439 fn __round__(
440 zelf: PyRef<Self>,
441 ndigits: OptionalOption<PyIntRef>,
442 vm: &VirtualMachine,
443 ) -> PyResult<PyRef<Self>> {
444 if let Some(ndigits) = ndigits.flatten() {
445 let ndigits = ndigits.as_bigint();
446 if let Some(ndigits) = ndigits.neg().to_u32()
449 && ndigits > 0
450 {
451 let sign = if zelf.value.is_negative() {
453 BigInt::from(-1)
454 } else {
455 BigInt::from(1)
456 };
457 let value = zelf.value.abs();
458
459 let pow10 = BigInt::from(10).pow(ndigits);
461 let quotient = &value / &pow10;
462 let rounded = "ient * &pow10;
463
464 let remainder = &value - &rounded;
466 let half_pow10 = &pow10 / BigInt::from(2);
467 let correction =
468 if remainder > half_pow10 || (remainder == half_pow10 && quotient.is_odd()) {
469 pow10
470 } else {
471 BigInt::from(0)
472 };
473 let rounded = (rounded + correction) * sign;
474 return Ok(vm.ctx.new_int(rounded));
475 }
476 }
477 Ok(zelf)
478 }
479
480 #[pymethod]
481 fn __trunc__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
482 zelf.__int__(vm)
483 }
484
485 #[pymethod]
486 fn __floor__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
487 zelf.__int__(vm)
488 }
489
490 #[pymethod]
491 fn __ceil__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
492 zelf.__int__(vm)
493 }
494
495 #[pymethod]
496 fn __format__(zelf: &Py<Self>, spec: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
497 if spec.is_empty() && !zelf.class().is(vm.ctx.types.int_type) {
499 return Ok(zelf.as_object().str(vm)?.as_wtf8().to_owned());
500 }
501 let format_spec =
502 FormatSpec::parse(spec.as_str()).map_err(|err| err.into_pyexception(vm))?;
503 let result = if format_spec.has_locale_format() {
504 let locale = crate::format::get_locale_info();
505 format_spec.format_int_locale(&zelf.value, &locale)
506 } else {
507 format_spec.format_int(&zelf.value)
508 };
509 result
510 .map(Wtf8Buf::from_string)
511 .map_err(|err| err.into_pyexception(vm))
512 }
513
514 #[pymethod]
515 fn __sizeof__(&self) -> usize {
516 core::mem::size_of::<Self>() + (((self.value.bits() + 7) & !7) / 8) as usize
517 }
518
519 #[pymethod]
520 fn as_integer_ratio(&self, vm: &VirtualMachine) -> (PyRef<Self>, i32) {
521 (vm.ctx.new_bigint(&self.value), 1)
522 }
523
524 #[pymethod]
525 fn bit_length(&self) -> u64 {
526 self.value.bits()
527 }
528
529 #[pymethod]
530 fn conjugate(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
531 zelf.__int__(vm)
532 }
533
534 #[pyclassmethod]
535 fn from_bytes(
536 cls: PyTypeRef,
537 args: IntFromByteArgs,
538 vm: &VirtualMachine,
539 ) -> PyResult<PyRef<Self>> {
540 let signed = args.signed.map_or(false, Into::into);
541 let value = match (args.byteorder, signed) {
542 (ArgByteOrder::Big, true) => BigInt::from_signed_bytes_be(args.bytes.as_bytes()),
543 (ArgByteOrder::Big, false) => BigInt::from_bytes_be(Sign::Plus, args.bytes.as_bytes()),
544 (ArgByteOrder::Little, true) => BigInt::from_signed_bytes_le(args.bytes.as_bytes()),
545 (ArgByteOrder::Little, false) => {
546 BigInt::from_bytes_le(Sign::Plus, args.bytes.as_bytes())
547 }
548 };
549 Self::with_value(cls, value, vm)
550 }
551
552 #[pymethod]
553 fn to_bytes(&self, args: IntToByteArgs, vm: &VirtualMachine) -> PyResult<PyBytes> {
554 let signed = args.signed.map_or(false, Into::into);
555 let byte_len = args.length;
556
557 let value = self.as_bigint();
558 match value.sign() {
559 Sign::Minus if !signed => {
560 return Err(vm.new_overflow_error("can't convert negative int to unsigned"));
561 }
562 Sign::NoSign => return Ok(vec![0u8; byte_len].into()),
563 _ => {}
564 }
565
566 let mut origin_bytes = match (args.byteorder, signed) {
567 (ArgByteOrder::Big, true) => value.to_signed_bytes_be(),
568 (ArgByteOrder::Big, false) => value.to_bytes_be().1,
569 (ArgByteOrder::Little, true) => value.to_signed_bytes_le(),
570 (ArgByteOrder::Little, false) => value.to_bytes_le().1,
571 };
572
573 let origin_len = origin_bytes.len();
574 if origin_len > byte_len {
575 return Err(vm.new_overflow_error("int too big to convert"));
576 }
577
578 let mut append_bytes = match value.sign() {
579 Sign::Minus => vec![255u8; byte_len - origin_len],
580 _ => vec![0u8; byte_len - origin_len],
581 };
582
583 let bytes = match args.byteorder {
584 ArgByteOrder::Big => {
585 let mut bytes = append_bytes;
586 bytes.append(&mut origin_bytes);
587 bytes
588 }
589 ArgByteOrder::Little => {
590 let mut bytes = origin_bytes;
591 bytes.append(&mut append_bytes);
592 bytes
593 }
594 };
595 Ok(bytes.into())
596 }
597
598 #[pygetset]
599 fn real(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
600 zelf.__int__(vm)
601 }
602
603 #[pygetset]
604 const fn imag(&self) -> usize {
605 0
606 }
607
608 #[pygetset]
609 fn numerator(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRefExact<Self> {
610 zelf.__int__(vm)
611 }
612
613 #[pygetset]
614 const fn denominator(&self) -> usize {
615 1
616 }
617
618 #[pymethod]
619 const fn is_integer(&self) -> bool {
620 true
621 }
622
623 #[pymethod]
624 fn bit_count(&self) -> u32 {
625 self.value.iter_u32_digits().map(|n| n.count_ones()).sum()
626 }
627
628 #[pymethod]
629 fn __getnewargs__(&self, vm: &VirtualMachine) -> PyObjectRef {
630 (self.value.clone(),).to_pyobject(vm)
631 }
632}
633
634#[pyclass]
635impl PyRef<PyInt> {
636 pub(crate) fn __int__(self, vm: &VirtualMachine) -> PyRefExact<PyInt> {
637 self.into_exact_or(&vm.ctx, |zelf| unsafe {
638 PyRefExact::new_unchecked(vm.ctx.new_bigint(&zelf.value))
640 })
641 }
642}
643
644impl Comparable for PyInt {
645 fn cmp(
646 zelf: &Py<Self>,
647 other: &PyObject,
648 op: PyComparisonOp,
649 _vm: &VirtualMachine,
650 ) -> PyResult<PyComparisonValue> {
651 let r = other
652 .downcast_ref::<Self>()
653 .map(|other| op.eval_ord(zelf.value.cmp(&other.value)));
654 Ok(PyComparisonValue::from_option(r))
655 }
656}
657
658impl Representable for PyInt {
659 #[inline]
660 fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
661 Ok(zelf.to_str_radix_10())
662 }
663}
664
665impl Hashable for PyInt {
666 #[inline]
667 fn hash(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<hash::PyHash> {
668 Ok(hash::hash_bigint(zelf.as_bigint()))
669 }
670}
671
672impl AsNumber for PyInt {
673 fn as_number() -> &'static PyNumberMethods {
674 static AS_NUMBER: PyNumberMethods = PyInt::AS_NUMBER;
675 &AS_NUMBER
676 }
677
678 #[inline]
679 fn clone_exact(zelf: &Py<Self>, vm: &VirtualMachine) -> PyRef<Self> {
680 vm.ctx.new_bigint(&zelf.value)
681 }
682}
683
684impl PyInt {
685 pub(super) const AS_NUMBER: PyNumberMethods = PyNumberMethods {
686 add: Some(|a, b, vm| Self::number_op(a, b, |a, b, _vm| a + b, vm)),
687 subtract: Some(|a, b, vm| Self::number_op(a, b, |a, b, _vm| a - b, vm)),
688 multiply: Some(|a, b, vm| Self::number_op(a, b, |a, b, _vm| a * b, vm)),
689 remainder: Some(|a, b, vm| Self::number_op(a, b, inner_mod, vm)),
690 divmod: Some(|a, b, vm| Self::number_op(a, b, inner_divmod, vm)),
691 power: Some(|a, b, c, vm| {
692 if let Some(a) = a.downcast_ref::<Self>() {
693 if vm.is_none(c) {
694 a.general_op(b.to_owned(), |a, b| inner_pow(a, b, vm), vm)
695 } else {
696 a.modpow(b.to_owned(), c.to_owned(), vm)
697 }
698 } else {
699 Ok(vm.ctx.not_implemented())
700 }
701 }),
702 negative: Some(|num, vm| (&Self::number_downcast(num).value).neg().to_pyresult(vm)),
703 positive: Some(|num, vm| Ok(Self::number_downcast_exact(num, vm).into())),
704 absolute: Some(|num, vm| Self::number_downcast(num).value.abs().to_pyresult(vm)),
705 boolean: Some(|num, _vm| Ok(!Self::number_downcast(num).value.is_zero())),
706 invert: Some(|num, vm| (&Self::number_downcast(num).value).not().to_pyresult(vm)),
707 lshift: Some(|a, b, vm| Self::number_op(a, b, inner_lshift, vm)),
708 rshift: Some(|a, b, vm| Self::number_op(a, b, inner_rshift, vm)),
709 and: Some(|a, b, vm| Self::number_op(a, b, |a, b, _vm| a & b, vm)),
710 xor: Some(|a, b, vm| Self::number_op(a, b, |a, b, _vm| a ^ b, vm)),
711 or: Some(|a, b, vm| Self::number_op(a, b, |a, b, _vm| a | b, vm)),
712 int: Some(|num, vm| Ok(Self::number_downcast_exact(num, vm).into())),
713 float: Some(|num, vm| {
714 let zelf = Self::number_downcast(num);
715 try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x).into())
716 }),
717 floor_divide: Some(|a, b, vm| Self::number_op(a, b, inner_floordiv, vm)),
718 true_divide: Some(|a, b, vm| Self::number_op(a, b, inner_truediv, vm)),
719 index: Some(|num, vm| Ok(Self::number_downcast_exact(num, vm).into())),
720 ..PyNumberMethods::NOT_IMPLEMENTED
721 };
722
723 fn number_op<F, R>(a: &PyObject, b: &PyObject, op: F, vm: &VirtualMachine) -> PyResult
724 where
725 F: FnOnce(&BigInt, &BigInt, &VirtualMachine) -> R,
726 R: ToPyResult,
727 {
728 if let (Some(a), Some(b)) = (a.downcast_ref::<Self>(), b.downcast_ref::<Self>()) {
729 op(&a.value, &b.value, vm).to_pyresult(vm)
730 } else {
731 Ok(vm.ctx.not_implemented())
732 }
733 }
734}
735
736#[derive(FromArgs)]
737pub struct IntOptions {
738 #[pyarg(positional, optional)]
739 val_options: OptionalArg<PyObjectRef>,
740 #[pyarg(any, optional)]
741 base: OptionalArg<PyObjectRef>,
742}
743
744#[derive(FromArgs)]
745struct IntFromByteArgs {
746 bytes: PyBytesInner,
747 #[pyarg(any, default = ArgByteOrder::Big)]
748 byteorder: ArgByteOrder,
749 #[pyarg(named, optional)]
750 signed: OptionalArg<ArgIntoBool>,
751}
752
753#[derive(FromArgs)]
754struct IntToByteArgs {
755 #[pyarg(any, default = 1)]
756 length: usize,
757 #[pyarg(any, default = ArgByteOrder::Big)]
758 byteorder: ArgByteOrder,
759 #[pyarg(named, optional)]
760 signed: OptionalArg<ArgIntoBool>,
761}
762
763fn try_int_radix(obj: &PyObject, base: u32, vm: &VirtualMachine) -> PyResult<BigInt> {
764 match_class!(match obj.to_owned() {
765 string @ PyStr => {
766 let s = string.as_wtf8().trim();
767 bytes_to_int(s.as_bytes(), base, vm.state.int_max_str_digits.load())
768 .map_err(|e| handle_bytes_to_int_err(e, obj, vm))
769 }
770 bytes @ PyBytes => {
771 bytes_to_int(bytes.as_bytes(), base, vm.state.int_max_str_digits.load())
772 .map_err(|e| handle_bytes_to_int_err(e, obj, vm))
773 }
774 bytearray @ PyByteArray => {
775 let inner = bytearray.borrow_buf();
776 bytes_to_int(&inner, base, vm.state.int_max_str_digits.load())
777 .map_err(|e| handle_bytes_to_int_err(e, obj, vm))
778 }
779 _ => Err(vm.new_type_error("int() can't convert non-string with explicit base")),
780 })
781}
782
783pub(crate) fn get_value(obj: &PyObject) -> &BigInt {
785 &obj.downcast_ref::<PyInt>().unwrap().value
786}
787
788pub fn try_to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult<f64> {
789 bigint_to_finite_float(int)
790 .ok_or_else(|| vm.new_overflow_error("int too large to convert to float"))
791}
792
793fn vectorcall_int(
794 zelf_obj: &PyObject,
795 args: Vec<PyObjectRef>,
796 nargs: usize,
797 kwnames: Option<&[PyObjectRef]>,
798 vm: &VirtualMachine,
799) -> PyResult {
800 let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
801 let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
802 (zelf.slots.new.load().unwrap())(zelf.to_owned(), func_args, vm)
803}
804
805pub(crate) fn init(context: &'static Context) {
806 PyInt::extend_class(context, context.types.int_type);
807 context
808 .types
809 .int_type
810 .slots
811 .vectorcall
812 .store(Some(vectorcall_int));
813}