syn/
bigint.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3use core::ops::{AddAssign, MulAssign};
4
5// For implementing base10_digits() accessor on LitInt.
6pub(crate) struct BigInt {
7    digits: Vec<u8>,
8}
9
10impl BigInt {
11    pub(crate) fn new() -> Self {
12        BigInt { digits: Vec::new() }
13    }
14
15    pub(crate) fn to_string(&self) -> String {
16        let mut repr = String::with_capacity(self.digits.len());
17
18        let mut has_nonzero = false;
19        for digit in self.digits.iter().rev() {
20            has_nonzero |= *digit != 0;
21            if has_nonzero {
22                repr.push((*digit + b'0') as char);
23            }
24        }
25
26        if repr.is_empty() {
27            repr.push('0');
28        }
29
30        repr
31    }
32
33    fn reserve_two_digits(&mut self) {
34        let len = self.digits.len();
35        let desired =
36            len + !self.digits.ends_with(&[0, 0]) as usize + !self.digits.ends_with(&[0]) as usize;
37        self.digits.resize(desired, 0);
38    }
39}
40
41impl AddAssign<u8> for BigInt {
42    // Assumes increment <16.
43    fn add_assign(&mut self, mut increment: u8) {
44        self.reserve_two_digits();
45
46        let mut i = 0;
47        while increment > 0 {
48            let sum = self.digits[i] + increment;
49            self.digits[i] = sum % 10;
50            increment = sum / 10;
51            i += 1;
52        }
53    }
54}
55
56impl MulAssign<u8> for BigInt {
57    // Assumes base <=16.
58    fn mul_assign(&mut self, base: u8) {
59        self.reserve_two_digits();
60
61        let mut carry = 0;
62        for digit in &mut self.digits {
63            let prod = *digit * base + carry;
64            *digit = prod % 10;
65            carry = prod / 10;
66        }
67    }
68}