1use crate::{SqlU256, U256};
7use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub};
8
9macro_rules! impl_binary_op {
11 ($trait:ident, $method:ident, $op:tt) => {
12 impl $trait for SqlU256 {
13 type Output = Self;
14
15 fn $method(self, rhs: Self) -> Self::Output {
16 SqlU256::from(self.0 $op rhs.0)
17 }
18 }
19
20 impl $trait<&SqlU256> for SqlU256 {
21 type Output = Self;
22
23 fn $method(self, rhs: &Self) -> Self::Output {
24 SqlU256::from(self.0 $op rhs.0)
25 }
26 }
27
28 impl $trait<SqlU256> for &SqlU256 {
29 type Output = SqlU256;
30
31 fn $method(self, rhs: SqlU256) -> Self::Output {
32 SqlU256::from(self.0 $op rhs.0)
33 }
34 }
35
36 impl $trait<&SqlU256> for &SqlU256 {
37 type Output = SqlU256;
38
39 fn $method(self, rhs: &SqlU256) -> Self::Output {
40 SqlU256::from(self.0 $op rhs.0)
41 }
42 }
43 };
44}
45
46macro_rules! impl_unary_op {
48 ($trait:ident, $method:ident, $op:tt) => {
49 impl $trait for SqlU256 {
50 type Output = Self;
51
52 fn $method(self) -> Self::Output {
53 SqlU256::from($op self.0)
54 }
55 }
56 };
57}
58
59macro_rules! impl_shift_op {
61 ($trait:ident, $method:ident, $op:tt, $rhs:ty) => {
62 impl $trait<$rhs> for SqlU256 {
63 type Output = Self;
64
65 fn $method(self, rhs: $rhs) -> Self::Output {
66 SqlU256::from(self.0 $op rhs)
67 }
68 }
69 };
70}
71
72macro_rules! impl_binary_assign_op {
74 ($trait:ident, $method:ident, $op:tt) => {
75 impl $trait for SqlU256 {
76 fn $method(&mut self, rhs: Self) {
77 self.0 = self.0 $op rhs.0;
78 }
79 }
80 impl $trait<&SqlU256> for SqlU256 {
81 fn $method(&mut self, rhs: &Self) {
82 self.0 = self.0 $op rhs.0;
83 }
84 }
85 };
86}
87
88use std::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
89impl_binary_assign_op!(AddAssign, add_assign, +);
90impl_binary_assign_op!(SubAssign, sub_assign, -);
91impl_binary_assign_op!(MulAssign, mul_assign, *);
92impl_binary_assign_op!(DivAssign, div_assign, /);
93impl_binary_assign_op!(RemAssign, rem_assign, %);
94
95impl_binary_op!(Add, add, +);
97impl_binary_op!(Sub, sub, -);
98impl_binary_op!(Mul, mul, *);
99impl_binary_op!(Div, div, /);
100impl_binary_op!(Rem, rem, %);
101
102impl BitAnd for SqlU256 {
104 type Output = Self;
105
106 fn bitand(self, rhs: Self) -> Self::Output {
107 SqlU256::from(self.0 & rhs.0)
108 }
109}
110
111impl BitOr for SqlU256 {
112 type Output = Self;
113
114 fn bitor(self, rhs: Self) -> Self::Output {
115 SqlU256::from(self.0 | rhs.0)
116 }
117}
118
119impl BitXor for SqlU256 {
120 type Output = Self;
121
122 fn bitxor(self, rhs: Self) -> Self::Output {
123 SqlU256::from(self.0 ^ rhs.0)
124 }
125}
126
127impl_unary_op!(Not, not, !);
129
130impl_shift_op!(Shl, shl, <<, usize);
132impl_shift_op!(Shr, shr, >>, usize);
133
134impl SqlU256 {
136 pub fn square(self) -> Self {
138 self * self
139 }
140
141 pub fn pow(self, exp: usize) -> Self {
143 SqlU256::from(self.0.pow(U256::from(exp)))
144 }
145
146 pub fn gcd(self, other: Self) -> Self {
148 let mut a = self.0;
149 let mut b = other.0;
150
151 while !b.is_zero() {
152 let temp = b;
153 b = a % b;
154 a = temp;
155 }
156 SqlU256::from(a)
158 }
159
160 pub fn lcm(self, other: Self) -> Self {
162 if self.0.is_zero() || other.0.is_zero() {
163 SqlU256::ZERO
164 } else {
165 let gcd = self.gcd(other);
166 (self / gcd) * other
167 }
168 }
169
170 pub fn checked_add(self, rhs: Self) -> Option<Self> {
172 self.0.checked_add(rhs.0).map(SqlU256::from)
173 }
174
175 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
177 self.0.checked_sub(rhs.0).map(SqlU256::from)
178 }
179
180 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
182 self.0.checked_mul(rhs.0).map(SqlU256::from)
183 }
184
185 pub fn checked_div(self, rhs: Self) -> Option<Self> {
187 if rhs.0.is_zero() {
188 None
189 } else {
190 Some(SqlU256::from(self.0 / rhs.0))
191 }
192 }
193
194 pub fn saturating_add(self, rhs: Self) -> Self {
196 SqlU256::from(self.0.saturating_add(rhs.0))
197 }
198
199 pub fn saturating_sub(self, rhs: Self) -> Self {
201 SqlU256::from(self.0.saturating_sub(rhs.0))
202 }
203
204 pub fn saturating_mul(self, rhs: Self) -> Self {
206 SqlU256::from(self.0.saturating_mul(rhs.0))
207 }
208
209 pub fn is_zero(self) -> bool {
211 self.0.is_zero()
212 }
213
214 pub fn min(self, other: Self) -> Self {
216 if self.0 < other.0 {
217 self
218 } else {
219 other
220 }
221 }
222
223 pub fn max(self, other: Self) -> Self {
225 if self.0 > other.0 {
226 self
227 } else {
228 other
229 }
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_basic_arithmetic() {
239 let a = SqlU256::from(100u64);
240 let b = SqlU256::from(50u64);
241
242 assert_eq!(a + b, SqlU256::from(150u64));
243 assert_eq!(a - b, SqlU256::from(50u64));
244 assert_eq!(a * b, SqlU256::from(5000u64));
245 assert_eq!(a / b, SqlU256::from(2u64));
246 assert_eq!(a % b, SqlU256::from(0u64));
247 }
248
249 #[test]
250 fn test_arithmetic_with_references() {
251 let a = SqlU256::from(100u64);
252 let b = SqlU256::from(50u64);
253
254 assert_eq!(&a + &b, SqlU256::from(150u64));
255 assert_eq!(a + &b, SqlU256::from(150u64));
256 assert_eq!(&a + b, SqlU256::from(150u64));
257 }
258
259 #[test]
260 fn test_bitwise_operations() {
261 let a = SqlU256::from(0b1100u64);
262 let b = SqlU256::from(0b1010u64);
263
264 assert_eq!(a & b, SqlU256::from(0b1000u64));
265 assert_eq!(a | b, SqlU256::from(0b1110u64));
266 assert_eq!(a ^ b, SqlU256::from(0b0110u64));
267 assert_eq!(!SqlU256::from(0u64), SqlU256::from(!U256::ZERO));
268 }
269
270 #[test]
271 fn test_shift_operations() {
272 let a = SqlU256::from(8u64);
273
274 assert_eq!(a << 1, SqlU256::from(16u64));
275 assert_eq!(a >> 1, SqlU256::from(4u64));
276 assert_eq!(a << 3, SqlU256::from(64u64));
277 assert_eq!(a >> 2, SqlU256::from(2u64));
278 }
279
280 #[test]
281 fn test_mathematical_operations() {
282 let a = SqlU256::from(5u64);
283 let _b = SqlU256::from(3u64);
284
285 assert_eq!(a.square(), SqlU256::from(25u64));
286 assert_eq!(a.pow(3), SqlU256::from(125u64));
287 assert_eq!(
288 SqlU256::from(12u64).gcd(SqlU256::from(8u64)),
289 SqlU256::from(4u64)
290 );
291 assert_eq!(
292 SqlU256::from(12u64).lcm(SqlU256::from(8u64)),
293 SqlU256::from(24u64)
294 );
295 }
296
297 #[test]
298 fn test_checked_operations() {
299 let a = SqlU256::from(100u64);
300 let b = SqlU256::from(50u64);
301 let zero = SqlU256::ZERO;
302
303 assert_eq!(a.checked_add(b), Some(SqlU256::from(150u64)));
304 assert_eq!(a.checked_sub(b), Some(SqlU256::from(50u64)));
305 assert_eq!(a.checked_mul(b), Some(SqlU256::from(5000u64)));
306 assert_eq!(a.checked_div(b), Some(SqlU256::from(2u64)));
307 assert_eq!(a.checked_div(zero), None);
308
309 assert_eq!(b.checked_sub(a), None);
311 }
312
313 #[test]
314 fn test_saturating_operations() {
315 let a = SqlU256::from(100u64);
316 let b = SqlU256::from(150u64);
317
318 assert_eq!(a.saturating_add(b), SqlU256::from(250u64));
319 assert_eq!(a.saturating_sub(b), SqlU256::ZERO);
320 assert_eq!(a.saturating_mul(b), SqlU256::from(15000u64));
321 }
322
323 #[test]
324 fn test_utility_functions() {
325 let a = SqlU256::from(100u64);
326 let b = SqlU256::from(50u64);
327 let zero = SqlU256::ZERO;
328
329 assert!(!a.is_zero());
330 assert!(zero.is_zero());
331 assert_eq!(a.min(b), b);
332 assert_eq!(a.max(b), a);
333 }
334
335 #[test]
336 fn test_division_by_zero_panics() {
337 let a = SqlU256::from(100u64);
338 let zero = SqlU256::ZERO;
339
340 let result = std::panic::catch_unwind(|| {
342 let _ = a / zero;
343 });
344 assert!(result.is_err());
345 }
346
347 #[test]
348 fn test_gcd_edge_cases() {
349 let zero = SqlU256::ZERO;
350 let five = SqlU256::from(5u64);
351
352 assert_eq!(zero.gcd(five), five);
353 assert_eq!(five.gcd(zero), five);
354 assert_eq!(zero.gcd(zero), zero);
355 }
356
357 #[test]
358 fn test_lcm_edge_cases() {
359 let zero = SqlU256::ZERO;
360 let five = SqlU256::from(5u64);
361
362 assert_eq!(zero.lcm(five), zero);
363 assert_eq!(five.lcm(zero), zero);
364 assert_eq!(zero.lcm(zero), zero);
365 }
366}