rustpython_vm/builtins/
int.rs

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            // missing feature: BigInt exp
119            // practically, exp over u64 is not possible to calculate anyway
120            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    // _PyLong_AsUnsignedLongMask
275    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                    // modular multiplicative inverse
426                    // based on rust-num/num-integer#10, should hopefully be published soon
427                    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            // round(12345, -2) == 12300
517            // If precision >= 0, then any integer is already rounded correctly
518            if let Some(ndigits) = ndigits.neg().to_u32() {
519                if ndigits > 0 {
520                    // Work with positive integers and negate at the end if necessary
521                    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                    // Divide and multiply by the power of 10 to get the approximate answer
529                    let pow10 = BigInt::from(10).pow(ndigits);
530                    let quotient = &value / &pow10;
531                    let rounded = &quotient * &pow10;
532
533                    // Malachite division uses floor rounding, Python uses half-even
534                    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    /// Returns the number of ones 1 an int. When the number is < 0,
705    /// then it returns the number of ones of the absolute value.
706    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            // TODO: this is actually safe. we need better interface
722            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
885// Retrieve inner int value:
886pub(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}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.