use crate::SqlUint;
use alloy::primitives::Uint;
use std::iter::{Product, Sum};
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub};
macro_rules! impl_binary_op {
($trait:ident, $method:ident, $op:tt) => {
impl<const BITS: usize, const LIMBS: usize> $trait for SqlUint<BITS, LIMBS> {
type Output = Self;
fn $method(self, rhs: Self) -> Self::Output {
SqlUint::from(self.0 $op rhs.0)
}
}
impl<const BITS: usize, const LIMBS: usize> $trait<&SqlUint<BITS, LIMBS>> for SqlUint<BITS, LIMBS> {
type Output = Self;
fn $method(self, rhs: &Self) -> Self::Output {
SqlUint::from(self.0 $op rhs.0)
}
}
impl<const BITS: usize, const LIMBS: usize> $trait<SqlUint<BITS, LIMBS>> for &SqlUint<BITS, LIMBS> {
type Output = SqlUint<BITS, LIMBS>;
fn $method(self, rhs: SqlUint<BITS, LIMBS>) -> Self::Output {
SqlUint::from(self.0 $op rhs.0)
}
}
impl<const BITS: usize, const LIMBS: usize> $trait<&SqlUint<BITS, LIMBS>> for &SqlUint<BITS, LIMBS> {
type Output = SqlUint<BITS, LIMBS>;
fn $method(self, rhs: &SqlUint<BITS, LIMBS>) -> Self::Output {
SqlUint::from(self.0 $op rhs.0)
}
}
};
}
macro_rules! impl_unary_op {
($trait:ident, $method:ident, $op:tt) => {
impl<const BITS: usize, const LIMBS: usize> $trait for SqlUint<BITS, LIMBS> {
type Output = Self;
fn $method(self) -> Self::Output {
SqlUint::from($op self.0)
}
}
};
}
macro_rules! impl_shift_op {
($trait:ident, $method:ident, $op:tt) => {
impl<const BITS: usize, const LIMBS: usize> $trait<usize> for SqlUint<BITS, LIMBS> {
type Output = Self;
fn $method(self, rhs: usize) -> Self::Output {
SqlUint::from(self.0 $op rhs)
}
}
};
}
macro_rules! impl_binary_assign_op {
($trait:ident, $method:ident, $op:tt) => {
impl<const BITS: usize, const LIMBS: usize> $trait for SqlUint<BITS, LIMBS> {
fn $method(&mut self, rhs: Self) {
self.0 = self.0 $op rhs.0;
}
}
impl<const BITS: usize, const LIMBS: usize> $trait<&SqlUint<BITS, LIMBS>> for SqlUint<BITS, LIMBS> {
fn $method(&mut self, rhs: &Self) {
self.0 = self.0 $op rhs.0;
}
}
};
}
use std::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
impl_binary_assign_op!(AddAssign, add_assign, +);
impl_binary_assign_op!(SubAssign, sub_assign, -);
impl_binary_assign_op!(MulAssign, mul_assign, *);
impl_binary_assign_op!(DivAssign, div_assign, /);
impl_binary_assign_op!(RemAssign, rem_assign, %);
impl_binary_op!(Add, add, +);
impl_binary_op!(Sub, sub, -);
impl_binary_op!(Mul, mul, *);
impl_binary_op!(Div, div, /);
impl_binary_op!(Rem, rem, %);
impl<const BITS: usize, const LIMBS: usize> BitAnd for SqlUint<BITS, LIMBS> {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
SqlUint::from(self.0 & rhs.0)
}
}
impl<const BITS: usize, const LIMBS: usize> BitOr for SqlUint<BITS, LIMBS> {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
SqlUint::from(self.0 | rhs.0)
}
}
impl<const BITS: usize, const LIMBS: usize> BitXor for SqlUint<BITS, LIMBS> {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
SqlUint::from(self.0 ^ rhs.0)
}
}
impl_unary_op!(Not, not, !);
impl_shift_op!(Shl, shl, <<);
impl_shift_op!(Shr, shr, >>);
impl<const BITS: usize, const LIMBS: usize> Sum for SqlUint<BITS, LIMBS> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(SqlUint::ZERO, |a, b| a + b)
}
}
impl<'a, const BITS: usize, const LIMBS: usize> Sum<&'a SqlUint<BITS, LIMBS>>
for SqlUint<BITS, LIMBS>
{
fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
iter.fold(SqlUint::ZERO, |a, b| a + *b)
}
}
impl<const BITS: usize, const LIMBS: usize> Product for SqlUint<BITS, LIMBS> {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(SqlUint(Uint::from(1u64)), |a, b| a * b)
}
}
impl<'a, const BITS: usize, const LIMBS: usize> Product<&'a SqlUint<BITS, LIMBS>>
for SqlUint<BITS, LIMBS>
{
fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
iter.fold(SqlUint(Uint::from(1u64)), |a, b| a * *b)
}
}
impl<const BITS: usize, const LIMBS: usize> SqlUint<BITS, LIMBS> {
pub fn square(self) -> Self {
self * self
}
pub fn pow(self, exp: usize) -> Self {
SqlUint::from(self.0.pow(Uint::<BITS, LIMBS>::from(exp)))
}
pub fn gcd(self, other: Self) -> Self {
let mut a = self.0;
let mut b = other.0;
while !b.is_zero() {
let temp = b;
b = a % b;
a = temp;
}
SqlUint::from(a)
}
pub fn lcm(self, other: Self) -> Self {
if self.0.is_zero() || other.0.is_zero() {
SqlUint::ZERO
} else {
let gcd = self.gcd(other);
(self / gcd) * other
}
}
pub fn checked_add(self, rhs: Self) -> Option<Self> {
self.0.checked_add(rhs.0).map(SqlUint::from)
}
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(SqlUint::from)
}
pub fn checked_mul(self, rhs: Self) -> Option<Self> {
self.0.checked_mul(rhs.0).map(SqlUint::from)
}
pub fn checked_div(self, rhs: Self) -> Option<Self> {
if rhs.0.is_zero() {
None
} else {
Some(SqlUint::from(self.0 / rhs.0))
}
}
pub fn saturating_add(self, rhs: Self) -> Self {
SqlUint::from(self.0.saturating_add(rhs.0))
}
pub fn saturating_sub(self, rhs: Self) -> Self {
SqlUint::from(self.0.saturating_sub(rhs.0))
}
pub fn saturating_mul(self, rhs: Self) -> Self {
SqlUint::from(self.0.saturating_mul(rhs.0))
}
pub fn is_zero(self) -> bool {
self.0.is_zero()
}
pub fn min(self, other: Self) -> Self {
if self.0 < other.0 { self } else { other }
}
pub fn max(self, other: Self) -> Self {
if self.0 > other.0 { self } else { other }
}
}
#[cfg(test)]
mod tests {
use crate::{SqlU128, SqlU256, U128, U256};
#[test]
fn test_basic_arithmetic_u256() {
let a = SqlU256::from(100u64);
let b = SqlU256::from(50u64);
assert_eq!(a + b, SqlU256::from(150u64));
assert_eq!(a - b, SqlU256::from(50u64));
assert_eq!(a * b, SqlU256::from(5000u64));
assert_eq!(a / b, SqlU256::from(2u64));
assert_eq!(a % b, SqlU256::from(0u64));
}
#[test]
fn test_arithmetic_with_references_u256() {
let a = SqlU256::from(100u64);
let b = SqlU256::from(50u64);
assert_eq!(&a + &b, SqlU256::from(150u64));
assert_eq!(a + &b, SqlU256::from(150u64));
assert_eq!(&a + b, SqlU256::from(150u64));
}
#[test]
fn test_bitwise_operations_u256() {
let a = SqlU256::from(0b1100u64);
let b = SqlU256::from(0b1010u64);
assert_eq!(a & b, SqlU256::from(0b1000u64));
assert_eq!(a | b, SqlU256::from(0b1110u64));
assert_eq!(a ^ b, SqlU256::from(0b0110u64));
}
#[test]
fn test_not_operation_u256() {
assert_eq!(!SqlU256::from(0u64), SqlU256::from(!U256::ZERO));
}
#[test]
fn test_shift_operations_u256() {
let a = SqlU256::from(8u64);
assert_eq!(a << 1, SqlU256::from(16u64));
assert_eq!(a >> 1, SqlU256::from(4u64));
assert_eq!(a << 3, SqlU256::from(64u64));
assert_eq!(a >> 2, SqlU256::from(2u64));
}
#[test]
fn test_mathematical_operations_u256() {
let a = SqlU256::from(5u64);
assert_eq!(a.square(), SqlU256::from(25u64));
assert_eq!(a.pow(3), SqlU256::from(125u64));
assert_eq!(SqlU256::from(12u64).gcd(SqlU256::from(8u64)), SqlU256::from(4u64));
assert_eq!(SqlU256::from(12u64).lcm(SqlU256::from(8u64)), SqlU256::from(24u64));
}
#[test]
fn test_checked_operations_u256() {
let a = SqlU256::from(100u64);
let b = SqlU256::from(50u64);
let zero = SqlU256::ZERO;
assert_eq!(a.checked_add(b), Some(SqlU256::from(150u64)));
assert_eq!(a.checked_sub(b), Some(SqlU256::from(50u64)));
assert_eq!(a.checked_mul(b), Some(SqlU256::from(5000u64)));
assert_eq!(a.checked_div(b), Some(SqlU256::from(2u64)));
assert_eq!(a.checked_div(zero), None);
assert_eq!(b.checked_sub(a), None);
}
#[test]
fn test_saturating_operations_u256() {
let a = SqlU256::from(100u64);
let b = SqlU256::from(150u64);
assert_eq!(a.saturating_add(b), SqlU256::from(250u64));
assert_eq!(a.saturating_sub(b), SqlU256::ZERO);
assert_eq!(a.saturating_mul(b), SqlU256::from(15000u64));
}
#[test]
fn test_utility_functions_u256() {
let a = SqlU256::from(100u64);
let b = SqlU256::from(50u64);
let zero = SqlU256::ZERO;
assert!(!a.is_zero());
assert!(zero.is_zero());
assert_eq!(a.min(b), b);
assert_eq!(a.max(b), a);
}
#[test]
fn test_gcd_edge_cases_u256() {
let zero = SqlU256::ZERO;
let five = SqlU256::from(5u64);
assert_eq!(zero.gcd(five), five);
assert_eq!(five.gcd(zero), five);
assert_eq!(zero.gcd(zero), zero);
}
#[test]
fn test_lcm_edge_cases_u256() {
let zero = SqlU256::ZERO;
let five = SqlU256::from(5u64);
assert_eq!(zero.lcm(five), zero);
assert_eq!(five.lcm(zero), zero);
assert_eq!(zero.lcm(zero), zero);
}
#[test]
fn test_basic_arithmetic_u128() {
let a = SqlU128::from(100u64);
let b = SqlU128::from(50u64);
assert_eq!(a + b, SqlU128::from(150u64));
assert_eq!(a - b, SqlU128::from(50u64));
assert_eq!(a * b, SqlU128::from(5000u64));
assert_eq!(a / b, SqlU128::from(2u64));
assert_eq!(a % b, SqlU128::from(0u64));
}
#[test]
fn test_arithmetic_with_references_u128() {
let a = SqlU128::from(100u64);
let b = SqlU128::from(50u64);
assert_eq!(&a + &b, SqlU128::from(150u64));
assert_eq!(a + &b, SqlU128::from(150u64));
assert_eq!(&a + b, SqlU128::from(150u64));
}
#[test]
fn test_bitwise_operations_u128() {
let a = SqlU128::from(0b1100u64);
let b = SqlU128::from(0b1010u64);
assert_eq!(a & b, SqlU128::from(0b1000u64));
assert_eq!(a | b, SqlU128::from(0b1110u64));
assert_eq!(a ^ b, SqlU128::from(0b0110u64));
}
#[test]
fn test_not_operation_u128() {
assert_eq!(!SqlU128::from(0u64), SqlU128::from(!U128::ZERO));
}
#[test]
fn test_shift_operations_u128() {
let a = SqlU128::from(8u64);
assert_eq!(a << 1, SqlU128::from(16u64));
assert_eq!(a >> 1, SqlU128::from(4u64));
}
#[test]
fn test_mathematical_operations_u128() {
let a = SqlU128::from(5u64);
assert_eq!(a.square(), SqlU128::from(25u64));
assert_eq!(a.pow(3), SqlU128::from(125u64));
}
#[test]
fn test_checked_operations_u128() {
let a = SqlU128::from(100u64);
let b = SqlU128::from(50u64);
let zero = SqlU128::ZERO;
assert_eq!(a.checked_add(b), Some(SqlU128::from(150u64)));
assert_eq!(a.checked_sub(b), Some(SqlU128::from(50u64)));
assert_eq!(a.checked_mul(b), Some(SqlU128::from(5000u64)));
assert_eq!(a.checked_div(b), Some(SqlU128::from(2u64)));
assert_eq!(a.checked_div(zero), None);
assert_eq!(b.checked_sub(a), None);
}
#[test]
fn test_saturating_operations_u128() {
let a = SqlU128::from(100u64);
let b = SqlU128::from(150u64);
assert_eq!(a.saturating_add(b), SqlU128::from(250u64));
assert_eq!(a.saturating_sub(b), SqlU128::ZERO);
}
#[test]
fn test_utility_functions_u128() {
let a = SqlU128::from(100u64);
let b = SqlU128::from(50u64);
let zero = SqlU128::ZERO;
assert!(!a.is_zero());
assert!(zero.is_zero());
assert_eq!(a.min(b), b);
assert_eq!(a.max(b), a);
}
#[test]
fn test_assign_ops_u128() {
let mut a = SqlU128::from(100u64);
a += SqlU128::from(50u64);
assert_eq!(a, SqlU128::from(150u64));
a -= SqlU128::from(30u64);
assert_eq!(a, SqlU128::from(120u64));
}
#[test]
fn test_sum_u256() {
let values = vec![
SqlU256::from(10u64),
SqlU256::from(20u64),
SqlU256::from(30u64),
];
let total: SqlU256 = values.iter().sum();
assert_eq!(total, SqlU256::from(60u64));
let total2: SqlU256 = values.into_iter().sum();
assert_eq!(total2, SqlU256::from(60u64));
}
#[test]
fn test_sum_empty_u256() {
let values: Vec<SqlU256> = vec![];
let total: SqlU256 = values.iter().sum();
assert_eq!(total, SqlU256::ZERO);
}
#[test]
fn test_product_u256() {
let values = vec![
SqlU256::from(2u64),
SqlU256::from(3u64),
SqlU256::from(4u64),
];
let prod: SqlU256 = values.iter().product();
assert_eq!(prod, SqlU256::from(24u64));
let prod2: SqlU256 = values.into_iter().product();
assert_eq!(prod2, SqlU256::from(24u64));
}
#[test]
fn test_product_empty_u256() {
let values: Vec<SqlU256> = vec![];
let prod: SqlU256 = values.iter().product();
assert_eq!(prod, SqlU256::from(1u64));
}
#[test]
fn test_sum_u128() {
let values = vec![
SqlU128::from(100u64),
SqlU128::from(200u64),
SqlU128::from(300u64),
];
let total: SqlU128 = values.iter().sum();
assert_eq!(total, SqlU128::from(600u64));
}
#[test]
fn test_product_u128() {
let values = vec![
SqlU128::from(2u64),
SqlU128::from(5u64),
];
let prod: SqlU128 = values.iter().product();
assert_eq!(prod, SqlU128::from(10u64));
}
}