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