use super::{Integer, Uint};
use crate::Exponent;
use crate::Int;
use num_integer::{Roots, Integer as IntegerTrait};
use crate::cast::CastFrom;
use num_traits::ops::overflowing::{OverflowingAdd, OverflowingMul, OverflowingSub};
use num_traits::{
AsPrimitive, Bounded, CheckedAdd, CheckedDiv, CheckedEuclid, CheckedMul, CheckedNeg,
CheckedRem, CheckedShl, CheckedShr, CheckedSub, ConstOne, ConstZero, Euclid, FromBytes,
FromPrimitive, MulAdd, MulAddAssign, Num, One, Pow, PrimInt, Saturating, SaturatingAdd,
SaturatingMul, SaturatingSub, Signed, ToBytes, ToPrimitive, Unsigned, WrappingAdd, WrappingMul,
WrappingNeg, WrappingShl, WrappingShr, WrappingSub, Zero,
};
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Bounded for Integer<S, N, B, OM> {
#[inline]
fn min_value() -> Self {
Self::MIN
}
#[inline]
fn max_value() -> Self {
Self::MAX
}
}
macro_rules! num_trait_impl {
($tr: ident, $method: ident, $ret: ty) => {
impl<const S: bool, const N: usize, const B: usize, const OM: u8> $tr for Integer<S, N, B, OM> {
#[inline]
fn $method(&self, rhs: &Self) -> $ret {
Self::$method(*self, *rhs)
}
}
};
}
num_trait_impl!(CheckedAdd, checked_add, Option<Self>);
num_trait_impl!(CheckedDiv, checked_div, Option<Self>);
num_trait_impl!(CheckedMul, checked_mul, Option<Self>);
num_trait_impl!(CheckedRem, checked_rem, Option<Self>);
num_trait_impl!(CheckedSub, checked_sub, Option<Self>);
num_trait_impl!(SaturatingAdd, saturating_add, Self);
num_trait_impl!(SaturatingMul, saturating_mul, Self);
num_trait_impl!(SaturatingSub, saturating_sub, Self);
num_trait_impl!(WrappingAdd, wrapping_add, Self);
num_trait_impl!(WrappingMul, wrapping_mul, Self);
num_trait_impl!(WrappingSub, wrapping_sub, Self);
num_trait_impl!(OverflowingAdd, overflowing_add, (Self, bool));
num_trait_impl!(OverflowingSub, overflowing_sub, (Self, bool));
num_trait_impl!(OverflowingMul, overflowing_mul, (Self, bool));
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CheckedNeg for Integer<S, N, B, OM> {
#[inline]
fn checked_neg(&self) -> Option<Self> {
Self::checked_neg(*self)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CheckedShl for Integer<S, N, B, OM> {
#[inline]
fn checked_shl(&self, rhs: Exponent) -> Option<Self> {
Self::checked_shl(*self, rhs)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CheckedShr for Integer<S, N, B, OM> {
#[inline]
fn checked_shr(&self, rhs: Exponent) -> Option<Self> {
Self::checked_shr(*self, rhs)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CheckedEuclid for Integer<S, N, B, OM> {
#[inline]
fn checked_div_euclid(&self, rhs: &Self) -> Option<Self> {
Self::checked_div_euclid(*self, *rhs)
}
#[inline]
fn checked_rem_euclid(&self, rhs: &Self) -> Option<Self> {
Self::checked_rem_euclid(*self, *rhs)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Euclid for Integer<S, N, B, OM> {
#[inline]
fn div_euclid(&self, rhs: &Self) -> Self {
Self::div_euclid(*self, *rhs)
}
#[inline]
fn rem_euclid(&self, rhs: &Self) -> Self {
Self::rem_euclid(*self, *rhs)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> WrappingNeg for Integer<S, N, B, OM> {
#[inline]
fn wrapping_neg(&self) -> Self {
Self::wrapping_neg(*self)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> WrappingShl for Integer<S, N, B, OM> {
#[inline]
fn wrapping_shl(&self, rhs: Exponent) -> Self {
Self::wrapping_shl(*self, rhs)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> WrappingShr for Integer<S, N, B, OM> {
#[inline]
fn wrapping_shr(&self, rhs: Exponent) -> Self {
Self::wrapping_shr(*self, rhs)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Pow<Exponent> for Integer<S, N, B, OM> {
type Output = Self;
#[inline]
fn pow(self, exp: Exponent) -> Self {
Self::pow(self, exp)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Saturating for Integer<S, N, B, OM> {
#[inline]
fn saturating_add(self, rhs: Self) -> Self {
Self::saturating_add(self, rhs)
}
#[inline]
fn saturating_sub(self, rhs: Self) -> Self {
Self::saturating_sub(self, rhs)
}
}
macro_rules! to_primitive_int {
($primitive: ty, $method: ident) => {
#[inline]
fn $method(&self) -> Option<$primitive> {
(*self).try_into().ok()
}
};
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> ToPrimitive for Integer<S, N, B, OM> {
to_primitive_int!(u8, to_u8);
to_primitive_int!(u16, to_u16);
to_primitive_int!(u32, to_u32);
to_primitive_int!(u64, to_u64);
to_primitive_int!(u128, to_u128);
to_primitive_int!(usize, to_usize);
to_primitive_int!(i8, to_i8);
to_primitive_int!(i16, to_i16);
to_primitive_int!(i32, to_i32);
to_primitive_int!(i64, to_i64);
to_primitive_int!(i128, to_i128);
to_primitive_int!(isize, to_isize);
#[inline]
fn to_f32(&self) -> Option<f32> {
Some(self.as_())
}
#[inline]
fn to_f64(&self) -> Option<f64> {
Some(self.as_())
}
}
macro_rules! impl_as_primitive_for_integer {
($($ty: ty), *) => {
$(
impl<const S: bool, const N: usize, const B: usize, const OM: u8> AsPrimitive<$ty> for Integer<S, N, B, OM> {
#[inline]
fn as_(self) -> $ty {
<$ty>::cast_from(self)
}
}
)*
}
}
impl_as_primitive_for_integer!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
);
macro_rules! impl_as_primitive_integer_for_primitive {
($($ty: ty), *) => {
$(
impl<const S: bool, const N: usize, const B: usize, const OM: u8> AsPrimitive<Integer<S, N, B, OM>> for $ty {
#[inline]
fn as_(self) -> Integer<S, N, B, OM> {
Integer::cast_from(self)
}
}
)*
}
}
impl_as_primitive_integer_for_primitive!(
u8, u16, u32, usize, u64, u128, i8, i16, i32, isize, i64, i128, f32, f64, char, bool
);
impl<const S: bool, const N: usize, const B: usize, const R: bool, const M: usize, const A: usize, const OM: u8> AsPrimitive<Integer<R, M, A, OM>>
for Integer<S, N, B, OM>
{
#[inline]
fn as_(self) -> Integer<R, M, A, OM> {
Integer::cast_from(self)
}
}
impl<const S: bool, const N: usize, const OM: u8> FromBytes for Integer<S, N, 0, OM> {
type Bytes = [u8; N];
#[inline]
fn from_be_bytes(bytes: &[u8; N]) -> Self {
Self::from_be_bytes(*bytes)
}
#[inline]
fn from_le_bytes(bytes: &[u8; N]) -> Self {
Self::from_le_bytes(*bytes)
}
}
impl<const S: bool, const N: usize, const OM: u8> ToBytes for Integer<S, N, 0, OM> {
type Bytes = [u8; N];
#[inline]
fn to_be_bytes(&self) -> [u8; N] {
Self::to_be_bytes(*self)
}
#[inline]
fn to_le_bytes(&self) -> [u8; N] {
Self::to_le_bytes(*self)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> MulAdd for Integer<S, N, B, OM> {
type Output = Self;
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self {
(self * a) + b
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> MulAddAssign for Integer<S, N, B, OM> {
#[inline]
fn mul_add_assign(&mut self, a: Self, b: Self) {
*self = self.mul_add(a, b);
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Num for Integer<S, N, B, OM> {
type FromStrRadixErr = crate::errors::ParseIntError;
#[inline]
fn from_str_radix(string: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
Self::from_str_radix(string, radix)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> num_traits::NumCast for Integer<S, N, B, OM> {
fn from<T: ToPrimitive>(_n: T) -> Option<Self> {
panic!(concat!(
crate::errors::err_prefix!(),
"`num_traits::NumCast` trait is not supported for ",
stringify!($Int)
))
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> One for Integer<S, N, B, OM> {
#[inline]
fn one() -> Self {
Self::ONE
}
#[inline]
fn is_one(&self) -> bool {
Self::is_one(&self)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> ConstOne for Integer<S, N, B, OM> {
const ONE: Self = Self::ONE;
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Zero for Integer<S, N, B, OM> {
#[inline]
fn zero() -> Self {
Self::ZERO
}
#[inline]
fn is_zero(&self) -> bool {
Self::is_zero(&self)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> ConstZero for Integer<S, N, B, OM> {
const ZERO: Self = Self::ZERO;
}
macro_rules! from_primitive_float {
($method: ident, $float: ty, $signed: ident) => {
#[inline]
fn $method(f: $float) -> Option<Self> {
if $signed {
if f.is_sign_negative() {
let i = Uint::$method(-f)?.force_sign();
return if i == Self::MIN {
Some(Self::MIN)
} else if i.is_negative_internal() {
None
} else {
Some(i.wrapping_neg())
};
} else {
let i = Uint::$method(f)?.force_sign();
return if i.is_negative_internal() {
None
} else {
Some(i)
};
}
}
match crate::cast::float::uint_try_from_float::<$float, Uint<N, B, OM>>(f) {
Ok(u) => Some(u.force_sign::<S>()),
Err(_) => None,
}
}
};
}
macro_rules! from_primitive_int {
($primitive: ty, $method: ident) => {
#[inline]
fn $method(n: $primitive) -> Option<Self> {
Self::try_from(n).ok()
}
};
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> FromPrimitive for Integer<S, N, B, OM> {
from_primitive_int!(u8, from_u8);
from_primitive_int!(u16, from_u16);
from_primitive_int!(u32, from_u32);
from_primitive_int!(u64, from_u64);
from_primitive_int!(u128, from_u128);
from_primitive_int!(usize, from_usize);
from_primitive_int!(i8, from_i8);
from_primitive_int!(i16, from_i16);
from_primitive_int!(i32, from_i32);
from_primitive_int!(i64, from_i64);
from_primitive_int!(i128, from_i128);
from_primitive_int!(isize, from_isize);
from_primitive_float!(from_f32, f32, S);
from_primitive_float!(from_f64, f64, S);
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> IntegerTrait for Integer<S, N, B, OM> {
#[inline]
fn div_floor(&self, other: &Self) -> Self {
Self::div_floor(*self, *other)
}
#[inline]
fn mod_floor(&self, other: &Self) -> Self {
let rem = self % other;
if S && rem.is_zero() {
return rem;
}
if rem.is_negative_internal() != other.is_negative_internal() {
rem + other
} else {
rem
}
}
#[inline]
fn gcd(&self, other: &Self) -> Self {
if S {
let gcd = self
.unsigned_abs_internal()
.gcd(&other.unsigned_abs_internal())
.force_sign();
if gcd == Self::MIN {
return crate::Int::MIN.force_sign();
}
return gcd;
}
let (mut a, mut b) = (*self, *other);
if a.is_zero() {
return b;
}
if b.is_zero() {
return a;
}
let mut a_tz = a.trailing_zeros();
let mut b_tz = b.trailing_zeros();
unsafe {
a = a.unchecked_shr_internal(a_tz);
b = b.unchecked_shr_internal(b_tz);
}
if b_tz > a_tz {
core::mem::swap(&mut a_tz, &mut b_tz);
}
loop {
if a < b {
core::mem::swap(&mut a, &mut b);
}
a -= b;
if a.is_zero() {
return unsafe { Self::unchecked_shl_internal(b, b_tz) };
}
unsafe {
a = a.unchecked_shr_internal(a.trailing_zeros());
}
}
}
#[inline]
fn lcm(&self, other: &Self) -> Self {
if self.is_zero() || other.is_zero() {
Self::ZERO
} else {
let gcd = (self / self.gcd(other)) * other;
if S {
gcd.force_sign::<true>().abs().force_sign()
} else {
gcd
}
}
}
#[inline]
fn divides(&self, other: &Self) -> bool {
self.is_multiple_of(other)
}
#[inline]
fn is_multiple_of(&self, other: &Self) -> bool {
if other.is_zero() {
return self.is_zero();
}
(self % other).is_zero()
}
#[inline]
fn is_even(&self) -> bool {
self.bytes[0] % 2 == 0
}
#[inline]
fn is_odd(&self) -> bool {
self.bytes[0] % 2 == 1
}
#[inline]
fn div_rem(&self, rhs: &Self) -> (Self, Self) {
if self.is_division_overflow(rhs) {
panic!(crate::errors::err_msg!("attempt to divide with overflow"));
}
if rhs.is_zero() {
panic!(crate::errors::err_msg!("attempt to divide by zero"));
}
self.div_rem_unchecked(*rhs)
}
}
macro_rules! prim_int_method {
{ $(fn $name: ident ($($arg: ident $(: $ty: ty)?), *) -> $ret: ty;) * } => {
$(
#[inline]
fn $name($($arg $(: $ty)?), *) -> $ret {
Self::$name($($arg), *)
}
)*
};
}
impl<const S: bool, const N: usize, const OM: u8> PrimInt for Integer<S, N, 0, OM> {
#[inline]
fn from_be(x: Self) -> Self {
if cfg!(target_endian = "big") {
x
} else {
x.swap_bytes()
}
}
#[inline]
fn from_le(x: Self) -> Self {
if cfg!(target_endian = "little") {
x
} else {
x.swap_bytes()
}
}
#[inline]
fn to_be(self) -> Self {
if cfg!(target_endian = "big") {
self
} else {
self.swap_bytes()
}
}
#[inline]
fn to_le(self) -> Self {
if cfg!(target_endian = "little") {
self
} else {
self.swap_bytes()
}
}
prim_int_method! {
fn count_ones(self) -> u32;
fn count_zeros(self) -> u32;
fn leading_zeros(self) -> u32;
fn trailing_zeros(self) -> u32;
fn rotate_left(self, n: u32) -> Self;
fn rotate_right(self, n: u32) -> Self;
fn swap_bytes(self) -> Self;
fn pow(self, exp: u32) -> Self;
fn leading_ones(self) -> u32;
fn trailing_ones(self) -> u32;
fn reverse_bits(self) -> Self;
}
#[inline]
fn signed_shl(self, n: u32) -> Self {
self << n
}
#[inline]
fn signed_shr(self, n: u32) -> Self {
(self.force_sign::<true>() >> n).force_sign()
}
#[inline]
fn unsigned_shl(self, n: u32) -> Self {
self << n
}
#[inline]
fn unsigned_shr(self, n: u32) -> Self {
(self.force_sign::<false>() >> n).force_sign()
}
}
impl<const N: usize, const B: usize, const OM: u8> Uint<N, B, OM> {
#[inline]
const fn nth_root_internal(self, n: Exponent) -> Self {
if self.is_zero() {
return self;
}
let bit_width = self.bit_width();
if n > bit_width {
return Self::ONE;
}
let e = if bit_width % n == 0 {
bit_width / n
} else {
bit_width / n + 1
};
let mut x = Self::power_of_two(e);
loop {
let y = (x.mul_u128_digit(n as u128 - 1).0.add(self.div(x.pow(n - 1))))
.div_rem_u64(n as u64)
.0;
if y.ge(&x) {
return x;
}
x = y;
}
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Roots for Integer<S, N, B, OM> {
#[inline]
fn sqrt(&self) -> Self {
self.isqrt()
}
#[inline]
fn cbrt(&self) -> Self {
self.nth_root(3)
}
#[inline]
fn nth_root(&self, n: u32) -> Self {
match n {
0 => panic!(crate::errors::err_msg!("attempt to calculate zeroth root")),
1 => *self,
2 => self.sqrt(),
_ => {
if self.is_negative_internal() {
let out = self.unsigned_abs_internal().nth_root(n);
return out.wrapping_neg().force_sign();
}
self.force_sign().nth_root_internal(n).force_sign()
}
}
}
}
impl<const N: usize, const B: usize, const OM: u8> Unsigned for Uint<N, B, OM> {}
impl<const N: usize, const B: usize, const OM: u8> Signed for Int<N, B, OM> {
#[inline]
fn abs(&self) -> Self {
Self::abs(*self)
}
#[inline]
fn abs_sub(&self, other: &Self) -> Self {
if self <= other {
Self::ZERO
} else {
*self - *other
}
}
#[inline]
fn signum(&self) -> Self {
Self::signum(*self)
}
#[inline]
fn is_positive(&self) -> bool {
Self::is_positive(*self)
}
#[inline]
fn is_negative(&self) -> bool {
self.is_negative_internal()
}
}
#[cfg(test)]
mod tests {
macro_rules! test_to_primitive {
($($prim: ty), *) => {
paste::paste! {
$(
test_bignum! {
function: <stest>::[<to_ $prim>](u: ref &stest)
}
)*
}
};
}
macro_rules! test_from_primitive {
($($prim: ty), *) => {
paste::paste! {
$(
test_bignum! {
function: <stest>::[<from_ $prim>](u: $prim),
cases: [
(stest::MIN as $prim)
]
}
)*
}
};
}
use super::*;
use crate::test::{TestConvert, test_bignum, debug_skip};
crate::test::test_all! {
testing integers;
crate::test::test_into! {
function: <stest as AsPrimitive>::as_,
into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64)
}
test_bignum! {
function: <stest as CheckedAdd>::checked_add(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as CheckedSub>::checked_sub(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as CheckedMul>::checked_mul(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as CheckedDiv>::checked_div(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as CheckedRem>::checked_rem(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as CheckedNeg>::checked_neg(a: ref &stest)
}
test_bignum! {
function: <stest as CheckedShl>::checked_shl(a: ref &stest, b: u8)
}
test_bignum! {
function: <stest as CheckedShr>::checked_shr(a: ref &stest, b: u8)
}
test_bignum! {
function: <stest as CheckedEuclid>::checked_div_euclid(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as CheckedEuclid>::checked_rem_euclid(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as Euclid>::div_euclid(a: ref &stest, b: ref &stest),
skip: a.checked_div_euclid(b).is_none()
}
test_bignum! {
function: <stest as Euclid>::rem_euclid(a: ref &stest, b: ref &stest),
skip: a.checked_rem_euclid(b).is_none()
}
test_bignum! {
function: <stest as SaturatingAdd>::saturating_add(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as SaturatingSub>::saturating_sub(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as SaturatingMul>::saturating_mul(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as Saturating>::saturating_add(a: stest, b: stest)
}
test_bignum! {
function: <stest as Saturating>::saturating_sub(a: stest, b: stest)
}
test_bignum! {
function: <stest as WrappingAdd>::wrapping_add(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as OverflowingAdd>::overflowing_add(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as WrappingSub>::wrapping_sub(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as OverflowingSub>::overflowing_sub(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as WrappingMul>::wrapping_mul(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as OverflowingMul>::overflowing_mul(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as WrappingNeg>::wrapping_neg(a: ref &stest)
}
test_bignum! {
function: <stest as WrappingShl>::wrapping_shl(a: ref &stest, b: u16)
}
test_bignum! {
function: <stest as WrappingShr>::wrapping_shr(a: ref &stest, b: u16)
}
test_bignum! {
function: <stest as One>::is_one(a: ref &stest)
}
test_bignum! {
function: <stest as Zero>::is_zero(a: ref &stest)
}
#[test]
fn one() {
assert_eq!(STEST::one(), TestConvert::into(stest::one()));
}
#[test]
fn zero() {
assert_eq!(STEST::zero(), TestConvert::into(stest::zero()));
}
#[test]
fn min_value() {
assert_eq!(STEST::min_value(), TestConvert::into(stest::min_value()));
}
#[test]
fn max_value() {
assert_eq!(STEST::max_value(), TestConvert::into(stest::max_value()));
}
test_bignum! {
function: <stest as MulAdd>::mul_add(a: stest, b: stest, c: stest),
skip: a.checked_mul(b).map(|d| d.checked_add(c)).flatten().is_none()
}
test_bignum! {
function: <stest as Roots>::sqrt(a: ref &stest),
skip: {
#[allow(unused_comparisons)]
let cond = a < 0;
cond
}
}
test_bignum! {
function: <stest as Roots>::cbrt(a: ref &stest)
}
test_bignum! {
function: <stest as Roots>::nth_root(a: ref &stest, n: u32),
skip: n == 0 || {
#[allow(unused_comparisons)]
let cond = a < 0;
n % 2 == 0 && cond || (n == 1 && cond && a == <stest>::MIN) }
}
test_to_primitive!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);
test_from_primitive!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);
test_bignum! {
function: <stest as IntegerTrait>::div_floor(a: ref &stest, b: ref &stest),
skip: b.is_zero()
}
test_bignum! {
function: <stest as IntegerTrait>::mod_floor(a: ref &stest, b: ref &stest),
skip: b.is_zero()
}
test_bignum! {
function: <stest as IntegerTrait>::lcm(a: ref &stest, b: ref &stest),
skip: {
#[allow(unused_comparisons)]
let cond = a.checked_mul(b).is_none() || (a < 0 && a == <stest>::MIN) || (b < 0 && b == <stest>::MIN); cond
},
cases: [(ref &(1 as stest), ref &(-1i8 as stest))]
}
test_bignum! {
function: <stest as IntegerTrait>::gcd(a: ref &stest, b: ref &stest),
skip: {
#[allow(unused_comparisons)]
let cond = <stest>::MIN < 0 && (a == <stest>::MIN && (b == <stest>::MIN || b == 0)) || (b == <stest>::MIN && (a == <stest>::MIN || a == 0));
cond
}
}
test_bignum! {
function: <stest as IntegerTrait>::is_multiple_of(a: ref &stest, b: ref &stest)
}
test_bignum! {
function: <stest as IntegerTrait>::is_even(a: ref &stest)
}
test_bignum! {
function: <stest as IntegerTrait>::is_odd(a: ref &stest)
}
test_bignum! {
function: <stest as IntegerTrait>::div_rem(a: ref &stest, b: ref &stest),
skip: b.is_zero()
}
test_bignum! {
function: <stest as PrimInt>::unsigned_shl(a: stest, n: u8),
skip: n >= <stest>::BITS as u8
}
test_bignum! {
function: <stest as PrimInt>::unsigned_shr(a: stest, n: u8),
skip: n >= <stest>::BITS as u8
}
test_bignum! {
function: <stest as PrimInt>::signed_shl(a: stest, n: u8),
skip: n >= <stest>::BITS as u8
}
test_bignum! {
function: <stest as PrimInt>::signed_shr(a: stest, n: u8),
skip: n >= <stest>::BITS as u8
}
}
crate::test::test_all! {
testing signed;
test_bignum! {
function: <stest as Signed>::abs(a: ref &stest),
skip: debug_skip!(a == <stest>::MIN)
}
test_bignum! {
function: <stest as Signed>::abs_sub(a: ref &stest, b: ref &stest),
skip: debug_skip!(a > b && a.checked_sub(b).is_none())
}
test_bignum! {
function: <stest as Signed>::signum(a: ref &stest)
}
test_bignum! {
function: <stest as Signed>::is_positive(a: ref &stest)
}
test_bignum! {
function: <stest as Signed>::is_negative(a: ref &stest)
}
}
}