1use std::{cmp::Ordering, fmt};
2
3use rustc_macros::{Decodable, Encodable};
4
5#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
14pub struct BigInt {
15 sign: Sign,
16 val: u128,
17}
18
19impl PartialOrd for BigInt {
20 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
21 Some(self.cmp(other))
22 }
23}
24
25impl Ord for BigInt {
26 fn cmp(&self, other: &Self) -> Ordering {
27 match (self.sign, other.sign) {
28 (Sign::Negative, Sign::NonNegative) => Ordering::Less,
29 (Sign::NonNegative, Sign::Negative) => Ordering::Greater,
30 (Sign::NonNegative, Sign::NonNegative) => self.val.cmp(&other.val),
31 (Sign::Negative, Sign::Negative) => other.val.cmp(&self.val),
32 }
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, PartialOrd, Ord)]
38enum Sign {
39 Negative,
40 NonNegative,
41}
42
43impl BigInt {
44 pub const ZERO: BigInt = BigInt { sign: Sign::NonNegative, val: 0 };
45 pub const ONE: BigInt = BigInt { sign: Sign::NonNegative, val: 1 };
46
47 pub fn is_negative(&self) -> bool {
48 matches!(self.sign, Sign::Negative)
49 }
50
51 pub fn abs(&self) -> u128 {
52 self.val
53 }
54
55 pub fn int_min(bit_width: u32) -> BigInt {
58 BigInt { sign: Sign::Negative, val: 1u128 << (bit_width - 1) }
59 }
60
61 pub fn int_max(bit_width: u32) -> BigInt {
64 (i128::MAX >> (128 - bit_width)).into()
65 }
66
67 pub fn uint_max(bit_width: u32) -> BigInt {
70 (u128::MAX >> (128 - bit_width)).into()
71 }
72
73 pub fn neg(&self) -> Self {
74 if self.val == 0 {
75 Self::ZERO } else {
77 Self {
78 sign: match self.sign {
79 Sign::Negative => Sign::NonNegative,
80 Sign::NonNegative => Sign::Negative,
81 },
82 val: self.val,
83 }
84 }
85 }
86
87 pub fn checked_add(&self, other: &Self) -> Option<Self> {
88 if self.sign == other.sign {
89 Some(Self { sign: self.sign, val: self.val.checked_add(other.val)? })
90 } else if self.val >= other.val {
91 let val = self.val - other.val;
92 if val == 0 { Some(Self::ZERO) } else { Some(Self { sign: self.sign, val }) }
93 } else {
94 Some(Self { sign: other.sign, val: other.val - self.val })
95 }
96 }
97
98 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
99 self.checked_add(&other.neg())
100 }
101
102 pub fn checked_mul(&self, other: &Self) -> Option<Self> {
103 let val = self.val.checked_mul(other.val)?;
104 if val == 0 {
105 Some(Self::ZERO)
106 } else {
107 let sign = if self.sign == other.sign { Sign::NonNegative } else { Sign::Negative };
108 Some(Self { sign, val })
109 }
110 }
111
112 pub fn checked_div(&self, other: &Self) -> Option<Self> {
113 if other.val == 0 {
114 return None;
115 } let val = self.val / other.val;
117 if val == 0 {
118 Some(Self::ZERO)
119 } else {
120 let sign = if self.sign == other.sign { Sign::NonNegative } else { Sign::Negative };
121 Some(Self { sign, val })
122 }
123 }
124
125 pub fn checked_rem(&self, other: &Self) -> Option<Self> {
126 if other.val == 0 {
127 return None;
128 } let val = self.val % other.val;
130 if val == 0 {
131 Some(Self::ZERO)
132 } else {
133 Some(Self { sign: self.sign, val })
135 }
136 }
137}
138
139impl From<usize> for BigInt {
140 fn from(val: usize) -> Self {
141 BigInt { sign: Sign::NonNegative, val: val as u128 }
142 }
143}
144
145impl From<u128> for BigInt {
146 fn from(val: u128) -> Self {
147 BigInt { sign: Sign::NonNegative, val }
148 }
149}
150
151impl From<i128> for BigInt {
152 fn from(val: i128) -> Self {
153 let sign = if val < 0 { Sign::Negative } else { Sign::NonNegative };
154 BigInt { sign, val: val.unsigned_abs() }
155 }
156}
157
158impl From<i32> for BigInt {
159 fn from(val: i32) -> Self {
160 if val < 0 {
162 BigInt { sign: Sign::Negative, val: -(val as i64) as u128 }
163 } else {
164 BigInt { sign: Sign::NonNegative, val: val as u128 }
165 }
166 }
167}
168
169impl From<u32> for BigInt {
170 fn from(val: u32) -> Self {
171 BigInt { sign: Sign::NonNegative, val: val as u128 }
172 }
173}
174
175impl From<u64> for BigInt {
176 fn from(val: u64) -> Self {
177 BigInt { sign: Sign::NonNegative, val: val as u128 }
178 }
179}
180
181impl fmt::Display for BigInt {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 match self.sign {
184 Sign::NonNegative => write!(f, "{}", self.val),
185 Sign::Negative => write!(f, "-{}", self.val),
186 }
187 }
188}