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