diff --git a/soroban-sdk/src/num.rs b/soroban-sdk/src/num.rs index 55ae4156e..fcdb39c00 100644 --- a/soroban-sdk/src/num.rs +++ b/soroban-sdk/src/num.rs @@ -206,8 +206,7 @@ impl U256 { pub const BITS: u32 = 256; fn is_zero(&self) -> bool { - const ZERO: U256Val = U256Val::from_u32(0); - self.val.as_val().get_payload() == ZERO.as_val().get_payload() + *self == U256::from_u32(&self.env, 0) } pub fn from_u32(env: &Env, u: u32) -> Self { @@ -440,13 +439,11 @@ impl I256 { pub const BITS: u32 = 256; fn is_zero(&self) -> bool { - const ZERO: I256Val = I256Val::from_i32(0); - self.val.as_val().get_payload() == ZERO.as_val().get_payload() + *self == I256::from_i32(&self.env, 0) } fn is_neg_one(&self) -> bool { - const NEG_ONE: I256Val = I256Val::from_i32(-1); - self.val.as_val().get_payload() == NEG_ONE.as_val().get_payload() + *self == I256::from_i32(&self.env, -1) } /// Returns the minimum value of I256 (-2^255). @@ -850,6 +847,61 @@ mod test { assert_eq!(u3.rem_euclid(&u4), U256::from_u32(&env, 3)); } + #[test] + fn test_u256_checked_arith() { + let env = Env::default(); + + let u1 = U256::from_u32(&env, 6); + let u2 = U256::from_u32(&env, 3); + assert_eq!(u1.checked_add(&u2), Some(U256::from_u32(&env, 9))); + assert_eq!(u1.checked_sub(&u2), Some(U256::from_u32(&env, 3))); + assert_eq!(u1.checked_mul(&u2), Some(U256::from_u32(&env, 18))); + assert_eq!(u1.checked_div(&u2), Some(U256::from_u32(&env, 2))); + assert_eq!(u1.checked_pow(2), Some(U256::from_u32(&env, 36))); + assert_eq!(u1.checked_shl(2), Some(U256::from_u32(&env, 24))); + assert_eq!(u1.checked_shr(1), Some(U256::from_u32(&env, 3))); + + let u3 = U256::from_u32(&env, 7); + let u4 = U256::from_u32(&env, 4); + assert_eq!(u3.checked_rem_euclid(&u4), Some(U256::from_u32(&env, 3))); + } + + #[test] + fn test_u256_checked_arith_overflow() { + let env = Env::default(); + + let zero = U256::from_u32(&env, 0); + let one = U256::from_u32(&env, 1); + let two = U256::from_u32(&env, 2); + let max = U256::from_parts(&env, u64::MAX, u64::MAX, u64::MAX, u64::MAX); + assert_eq!(max.checked_add(&one), None); + assert_eq!(zero.checked_sub(&one), None); + assert_eq!(max.checked_mul(&two), None); + assert_eq!(one.checked_div(&zero), None); + assert_eq!(max.checked_pow(2), None); + assert_eq!(one.checked_shl(256), None); + assert_eq!(one.checked_shr(256), None); + assert_eq!(one.checked_rem_euclid(&zero), None); + + let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0); + let one_from_parts = U256::from_parts(&env, 0, 0, 0, 1); + assert_eq!(one.checked_div(&zero_from_parts), None); + assert_eq!(zero.checked_sub(&one_from_parts), None); + } + + #[test] + fn test_u256_is_zero() { + let env = Env::default(); + + let zero = U256::from_u32(&env, 0); + let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0); + let non_zero = U256::from_u32(&env, 1); + + assert!(zero.is_zero()); + assert!(zero_from_parts.is_zero()); + assert!(!non_zero.is_zero()); + } + #[test] fn test_i256_arith() { let env = Env::default(); @@ -868,4 +920,89 @@ mod test { let u4 = I256::from_i32(&env, 4); assert_eq!(u3.rem_euclid(&u4), I256::from_i32(&env, 1)); } + + #[test] + fn test_i256_checked_arith() { + let env = Env::default(); + + let i1 = I256::from_i32(&env, -6); + let i2 = I256::from_i32(&env, 3); + assert_eq!(i1.checked_add(&i2), Some(I256::from_i32(&env, -3))); + assert_eq!(i1.checked_sub(&i2), Some(I256::from_i32(&env, -9))); + assert_eq!(i1.checked_mul(&i2), Some(I256::from_i32(&env, -18))); + assert_eq!(i1.checked_div(&i2), Some(I256::from_i32(&env, -2))); + assert_eq!(i1.checked_pow(2), Some(I256::from_i32(&env, 36))); + assert_eq!(i1.checked_shl(2), Some(I256::from_i32(&env, -24))); + assert_eq!(i1.checked_shr(1), Some(I256::from_i32(&env, -3))); + + let u3 = I256::from_i32(&env, -7); + let u4 = I256::from_i32(&env, 4); + assert_eq!(u3.checked_rem_euclid(&u4), Some(I256::from_i32(&env, 1))); + } + + #[test] + fn test_i256_checked_arith_overflow() { + let env = Env::default(); + + let zero = I256::from_i32(&env, 0); + let one = I256::from_i32(&env, 1); + let negative_one = I256::from_i32(&env, -1); + let two = I256::from_i32(&env, 2); + let max = I256::from_parts(&env, i64::MAX, u64::MAX, u64::MAX, u64::MAX); + let min = I256::from_parts(&env, i64::MIN, 0, 0, 0); + assert_eq!(max.checked_add(&one), None); + assert_eq!(min.checked_sub(&one), None); + assert_eq!(max.checked_mul(&two), None); + assert_eq!(one.checked_div(&zero), None); + assert_eq!(min.checked_div(&negative_one), None); + assert_eq!(max.checked_pow(2), None); + assert_eq!(one.checked_shl(256), None); + assert_eq!(one.checked_shr(256), None); + assert_eq!(one.checked_rem_euclid(&zero), None); + + let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0); + let one_from_parts = I256::from_parts(&env, 0, 0, 0, 1); + assert_eq!(one.checked_div(&zero_from_parts), None); + assert_eq!(min.checked_sub(&one_from_parts), None); + } + + #[test] + fn test_i256_is_zero() { + let env = Env::default(); + + let zero = I256::from_i32(&env, 0); + let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0); + let non_zero = I256::from_i32(&env, 1); + + assert!(zero.is_zero()); + assert!(zero_from_parts.is_zero()); + assert!(!non_zero.is_zero()); + } + + #[test] + fn test_i256_is_neg_one() { + let env = Env::default(); + + let negative_one = I256::from_i32(&env, -1); + let negative_one_from_parts = I256::from_parts(&env, -1, u64::MAX, u64::MAX, u64::MAX); + let negative_two = I256::from_i32(&env, -2); + + assert!(negative_one.is_neg_one()); + assert!(negative_one_from_parts.is_neg_one()); + assert!(!negative_two.is_neg_one()); + } + + #[test] + fn test_i256_is_div_overflow() { + let env = Env::default(); + + let zero = I256::from_i32(&env, 0); + let negative_one = I256::from_i32(&env, -1); + let min = I256::min_value(&env); + + assert!(!zero.is_div_overflow(&negative_one)); + + assert!(negative_one.is_div_overflow(&zero)); + assert!(min.is_div_overflow(&negative_one)); + } }