diff --git a/Cargo.toml b/Cargo.toml index dd61c92..ba18ac0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bnum" -version = "0.6.0" +version = "0.7.0" authors = ["isaac-holt "] edition = "2021" license = "MIT OR Apache-2.0" @@ -26,6 +26,7 @@ num-traits = { version = "0.2.15", optional = true, default-features = false } serde = { version = "1.0.152", features = ["derive"], optional = true, default-features = false } serde-big-array = { version = "0.4.1", optional = true, default-features = false } rand = { version = "0.8.5", features = ["min_const_gen", "small_rng", "std_rng"], optional = true, default-features = false } +arbitrary = { version = "1.3.0", features = ["derive"], optional = true } [dev-dependencies] quickcheck = "1.0.3" @@ -36,4 +37,4 @@ lto = true # enable link-time optimisation for faster runtime, but slower compil opt-level = 3 # maximum optimisation level for faster runtime, but slower compile time [package.metadata.docs.rs] -features = ["nightly", "serde", "numtraits", "rand"] \ No newline at end of file +features = ["nightly", "serde", "numtraits", "rand", "arbitrary"] \ No newline at end of file diff --git a/README.md b/README.md index 1931a3f..22cb2e4 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,13 @@ In version `0.1.0`, the `from_be` and `to_be` methods on all integers were imple To install and use `bnum`, simply add the following line to your `Cargo.toml` file in the `[dependencies]` section: ```toml -bnum = "0.6.0" +bnum = "0.7.0" ``` Or, to enable various `bnum` features as well, add for example this line instead: ```toml -bnum = { version = "0.6.0", features = ["rand"] } # enables the "rand" feature +bnum = { version = "0.7.0", features = ["rand"] } # enables the "rand" feature ``` ## Example Usage @@ -92,6 +92,10 @@ assert_eq!(neg_one.count_ones(), 80); // signed integers are stored in two's com ## Features +### Fuzzing + +The `arbitrary` feature derives the [`Arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html) trait from the [`arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/) crate. **Note: currently, this feature cannot be used with `no_std`.** + ### Random Number Generation The `rand` feature allows creation of random bnum integers via the [`rand`](https://docs.rs/rand/latest/rand/) crate. diff --git a/changes/v0.7.0 b/changes/v0.7.0 index 70a1b3a..d174afd 100644 --- a/changes/v0.7.0 +++ b/changes/v0.7.0 @@ -1,3 +1,3 @@ Removal of `const` impls of standard library traits, addition of equivalent methods defined on the integer types themselves. -`abs_diff`, `BUint::{overflowing_neg, wrapping_neg}` now `const`. -(TODO): implementation of `Arbitrary`. \ No newline at end of file +Following methods are now `const`: `abs_diff`, `BUint::{overflowing_neg, wrapping_neg}`, `wrapping_{shr, shl}`, `overflowing_{shr, shl}`, `checked_{shr, shl}`, `rotate_left`, `rotate_right`, `from_be_slice`, `from_le_slice`. +Implementation of `Arbitrary`. \ No newline at end of file diff --git a/src/bint/cast.rs b/src/bint/cast.rs index 9cac81d..76406f8 100644 --- a/src/bint/cast.rs +++ b/src/bint/cast.rs @@ -1,134 +1,134 @@ macro_rules! bint_as { - ($BInt: ident, $Digit: ident; $($int: ty), *) => { - $( - impl_const! { - impl const CastFrom<$BInt> for $int { - #[inline] - fn cast_from(from: $BInt) -> Self { - if from.is_negative() { - let digits = from.bits.digits; - let mut out = !0; - let mut i = 0; - while i << digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N { - out &= !((!digits[i]) as $int << (i << digit::$Digit::BIT_SHIFT)); - i += 1; - } - out - } else { - <$int>::cast_from(from.bits) - } - } - } - } - )* - }; + ($BInt: ident, $Digit: ident; $($int: ty), *) => { + $( + impl_const! { + impl const CastFrom<$BInt> for $int { + #[inline] + fn cast_from(from: $BInt) -> Self { + if from.is_negative() { + let digits = from.bits.digits; + let mut out = !0; + let mut i = 0; + while i << digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N { + out &= !((!digits[i]) as $int << (i << digit::$Digit::BIT_SHIFT)); + i += 1; + } + out + } else { + <$int>::cast_from(from.bits) + } + } + } + } + )* + }; } macro_rules! as_bint { - ($BInt: ident, $BUint: ident; $($ty: ty), *) => { - $(impl_const! { - impl const CastFrom<$ty> for $BInt { - #[inline] - fn cast_from(from: $ty) -> Self { - Self::from_bits($BUint::cast_from(from)) - } - } - })* - } + ($BInt: ident, $BUint: ident; $($ty: ty), *) => { + $(impl_const! { + impl const CastFrom<$ty> for $BInt { + #[inline] + fn cast_from(from: $ty) -> Self { + Self::from_bits($BUint::cast_from(from)) + } + } + })* + } } use crate::cast::CastFrom; -use crate::nightly::impl_const; use crate::digit; +use crate::nightly::impl_const; macro_rules! cast { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - bint_as!($BInt, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + ($BUint: ident, $BInt: ident, $Digit: ident) => { + bint_as!($BInt, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - impl CastFrom<$BInt> for f32 { - #[inline] - fn cast_from(from: $BInt) -> Self { - let f = f32::cast_from(from.unsigned_abs()); - if from.is_negative() { - -f - } else { - f - } - } - } + impl CastFrom<$BInt> for f32 { + #[inline] + fn cast_from(from: $BInt) -> Self { + let f = f32::cast_from(from.unsigned_abs()); + if from.is_negative() { + -f + } else { + f + } + } + } - impl CastFrom<$BInt> for f64 { - #[inline] - fn cast_from(from: $BInt) -> Self { - let f = f64::cast_from(from.unsigned_abs()); - if from.is_negative() { - -f - } else { - f - } - } - } + impl CastFrom<$BInt> for f64 { + #[inline] + fn cast_from(from: $BInt) -> Self { + let f = f64::cast_from(from.unsigned_abs()); + if from.is_negative() { + -f + } else { + f + } + } + } - as_bint!($BInt, $BUint; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool, char); + as_bint!($BInt, $BUint; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool, char); - impl_const! { - impl const CastFrom<$BUint> for $BInt { - #[inline] - fn cast_from(from: $BUint) -> Self { - Self::from_bits($BUint::cast_from(from)) - } - } - } + impl_const! { + impl const CastFrom<$BUint> for $BInt { + #[inline] + fn cast_from(from: $BUint) -> Self { + Self::from_bits($BUint::cast_from(from)) + } + } + } - impl_const! { - impl const CastFrom<$BInt> for $BInt { - #[inline] - fn cast_from(from: $BInt) -> Self { - Self::from_bits($BUint::cast_from(from)) - } - } - } + impl_const! { + impl const CastFrom<$BInt> for $BInt { + #[inline] + fn cast_from(from: $BInt) -> Self { + Self::from_bits($BUint::cast_from(from)) + } + } + } - macro_rules! cast_from_float { - ($f: ty) => { - #[inline] - fn cast_from(from: $f) -> Self { - if from.is_sign_negative() { - let u = $BUint::::cast_from(-from); - if u >= Self::MIN.to_bits() { - Self::MIN - } else { - -Self::from_bits(u) - } - } else { - let u = $BUint::::cast_from(from); - let i = Self::from_bits(u); - if i.is_negative() { - Self::MAX - } else { - i - } - } - } - }; - } + macro_rules! cast_from_float { + ($f: ty) => { + #[inline] + fn cast_from(from: $f) -> Self { + if from.is_sign_negative() { + let u = $BUint::::cast_from(-from); + if u >= Self::MIN.to_bits() { + Self::MIN + } else { + -Self::from_bits(u) + } + } else { + let u = $BUint::::cast_from(from); + let i = Self::from_bits(u); + if i.is_negative() { + Self::MAX + } else { + i + } + } + } + }; + } - impl CastFrom for $BInt { - cast_from_float!(f32); - } + impl CastFrom for $BInt { + cast_from_float!(f32); + } - impl CastFrom for $BInt { - cast_from_float!(f64); - } + impl CastFrom for $BInt { + cast_from_float!(f64); + } - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - crate::int::cast::tests!(itest); - } - } - }; + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + crate::int::cast::tests!(itest); + } + } + }; } crate::macro_impl!(cast); diff --git a/src/bint/checked.rs b/src/bint/checked.rs index db65102..88ad4a6 100644 --- a/src/bint/checked.rs +++ b/src/bint/checked.rs @@ -1,18 +1,18 @@ macro_rules! checked_ilog { - ($method: ident $(, $base: ident: $ty: ty)?) => { - crate::nightly::const_fn! { - #[doc = doc::checked::$method!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn $method(self $(, $base: $ty)?) -> Option { - if self.is_negative() { - None - } else { - self.bits.$method($($base)?) - } - } - } - } + ($method: ident $(, $base: ident: $ty: ty)?) => { + crate::nightly::const_fn! { + #[doc = doc::checked::$method!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn $method(self $(, $base: $ty)?) -> Option { + if self.is_negative() { + None + } else { + self.bits.$method($($base)?) + } + } + } + } } use crate::doc; @@ -51,14 +51,14 @@ macro_rules! checked { tuple_to_option(self.overflowing_sub_unsigned(rhs)) } - #[doc = doc::checked::checked_mul!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_mul(self, rhs: Self) -> Option { - tuple_to_option(self.overflowing_mul(rhs)) - } - - crate::nightly::const_fns! { + #[doc = doc::checked::checked_mul!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_mul(self, rhs: Self) -> Option { + tuple_to_option(self.overflowing_mul(rhs)) + } + + crate::nightly::const_fns! { #[doc = doc::checked::checked_div!(I)] #[must_use = doc::must_use_op!()] #[inline] @@ -102,66 +102,64 @@ macro_rules! checked { tuple_to_option(self.overflowing_rem_euclid(rhs)) } } - } + } - #[doc = doc::checked::checked_neg!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_neg(self) -> Option { - tuple_to_option(self.overflowing_neg()) - } + #[doc = doc::checked::checked_neg!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_neg(self) -> Option { + tuple_to_option(self.overflowing_neg()) + } - crate::nightly::const_fns! { - #[doc = doc::checked::checked_shl!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_shl(self, rhs: ExpType) -> Option { - tuple_to_option(self.overflowing_shl(rhs)) - } + #[doc = doc::checked::checked_shl!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_shl(self, rhs: ExpType) -> Option { + tuple_to_option(self.overflowing_shl(rhs)) + } - #[doc = doc::checked::checked_shr!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_shr(self, rhs: ExpType) -> Option { - tuple_to_option(self.overflowing_shr(rhs)) - } - } + #[doc = doc::checked::checked_shr!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_shr(self, rhs: ExpType) -> Option { + tuple_to_option(self.overflowing_shr(rhs)) + } - #[doc = doc::checked::checked_abs!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_abs(self) -> Option { - tuple_to_option(self.overflowing_abs()) - } + #[doc = doc::checked::checked_abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_abs(self) -> Option { + tuple_to_option(self.overflowing_abs()) + } - #[doc = doc::checked::checked_pow!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_pow(self, pow: ExpType) -> Option { - match self.unsigned_abs().checked_pow(pow) { - Some(u) => { - let out = Self::from_bits(u); - let neg = self.is_negative(); - if !neg || pow & 1 == 0 { - if out.is_negative() { - None - } else { - Some(out) - } - } else { - let out = out.wrapping_neg(); - if !out.is_negative() { - None - } else { - Some(out) - } - } - }, - None => None, - } - } + #[doc = doc::checked::checked_pow!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_pow(self, pow: ExpType) -> Option { + match self.unsigned_abs().checked_pow(pow) { + Some(u) => { + let out = Self::from_bits(u); + let neg = self.is_negative(); + if !neg || pow & 1 == 0 { + if out.is_negative() { + None + } else { + Some(out) + } + } else { + let out = out.wrapping_neg(); + if !out.is_negative() { + None + } else { + Some(out) + } + } + } + None => None, + } + } - crate::nightly::const_fns! { + crate::nightly::const_fns! { #[doc = doc::checked::checked_next_multiple_of!(I)] #[must_use = doc::must_use_op!()] #[inline] diff --git a/src/bint/cmp.rs b/src/bint/cmp.rs index ef71ccb..9ec9dc5 100644 --- a/src/bint/cmp.rs +++ b/src/bint/cmp.rs @@ -12,7 +12,7 @@ macro_rules! cmp { } } - impl Eq for $BInt {} + impl Eq for $BInt {} impl_const! { impl const PartialOrd for $BInt { @@ -37,8 +37,8 @@ macro_rules! cmp { #[inline] fn min(self, other: Self) -> Self { - Self::min(self, other) - } + Self::min(self, other) + } #[inline] fn clamp(self, min: Self, max: Self) -> Self { diff --git a/src/bint/const_trait_fillers.rs b/src/bint/const_trait_fillers.rs index 8f65d10..5f522bc 100644 --- a/src/bint/const_trait_fillers.rs +++ b/src/bint/const_trait_fillers.rs @@ -1,98 +1,98 @@ -use core::cmp::Ordering; -use crate::ExpType; use crate::doc; +use crate::ExpType; +use core::cmp::Ordering; macro_rules! const_trait_fillers { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::const_trait_fillers::impl_desc!()] - impl $BInt { - #[inline] - pub const fn bitand(self, rhs: Self) -> Self { - Self::from_bits(self.bits.bitand(rhs.bits)) - } + ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[doc = doc::const_trait_fillers::impl_desc!()] + impl $BInt { + #[inline] + pub const fn bitand(self, rhs: Self) -> Self { + Self::from_bits(self.bits.bitand(rhs.bits)) + } + + #[inline] + pub const fn bitor(self, rhs: Self) -> Self { + Self::from_bits(self.bits.bitor(rhs.bits)) + } - #[inline] - pub const fn bitor(self, rhs: Self) -> Self { - Self::from_bits(self.bits.bitor(rhs.bits)) - } + #[inline] + pub const fn bitxor(self, rhs: Self) -> Self { + Self::from_bits(self.bits.bitxor(rhs.bits)) + } - #[inline] - pub const fn bitxor(self, rhs: Self) -> Self { - Self::from_bits(self.bits.bitxor(rhs.bits)) - } - - #[inline] - pub const fn not(self) -> Self { - Self::from_bits(self.bits.not()) - } + #[inline] + pub const fn not(self) -> Self { + Self::from_bits(self.bits.not()) + } - #[inline] - pub const fn eq(&self, other: &Self) -> bool { - $BUint::eq(&self.bits, &other.bits) - } + #[inline] + pub const fn eq(&self, other: &Self) -> bool { + $BUint::eq(&self.bits, &other.bits) + } - #[inline] - pub const fn ne(&self, other: &Self) -> bool { - !Self::eq(self, other) - } + #[inline] + pub const fn ne(&self, other: &Self) -> bool { + !Self::eq(self, other) + } - #[inline] - pub const fn cmp(&self, other: &Self) -> Ordering { - let s1 = self.signed_digit(); - let s2 = other.signed_digit(); + #[inline] + pub const fn cmp(&self, other: &Self) -> Ordering { + let s1 = self.signed_digit(); + let s2 = other.signed_digit(); - // Don't use match here as `cmp` is not yet const for primitive integers - #[allow(clippy::comparison_chain)] - if s1 == s2 { - $BUint::cmp(&self.bits, &other.bits) - } else if s1 > s2 { - Ordering::Greater - } else { - Ordering::Less - } - } + // Don't use match here as `cmp` is not yet const for primitive integers + #[allow(clippy::comparison_chain)] + if s1 == s2 { + $BUint::cmp(&self.bits, &other.bits) + } else if s1 > s2 { + Ordering::Greater + } else { + Ordering::Less + } + } - crate::int::cmp::impls!(); - #[inline] - pub const fn neg(self) -> Self { - #[cfg(debug_assertions)] - return crate::errors::option_expect!(self.checked_neg(), crate::errors::err_msg!("attempt to negate with overflow")); + crate::int::cmp::impls!(); + #[inline] + pub const fn neg(self) -> Self { + #[cfg(debug_assertions)] + return crate::errors::option_expect!(self.checked_neg(), crate::errors::err_msg!("attempt to negate with overflow")); - #[cfg(not(debug_assertions))] - self.wrapping_neg() - } + #[cfg(not(debug_assertions))] + self.wrapping_neg() + } - crate::int::ops::trait_fillers!(); + crate::int::ops::trait_fillers!(); - crate::nightly::const_fn! { - #[inline] - pub const fn div(self, rhs: Self) -> Self { - if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { - panic!(crate::errors::err_msg!("attempt to divide with overflow")) - } else { - if rhs.is_zero() { - crate::errors::div_zero!() - } - self.div_rem_unchecked(rhs).0 - } - } - } + crate::nightly::const_fn! { + #[inline] + pub const fn div(self, rhs: Self) -> Self { + if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { + panic!(crate::errors::err_msg!("attempt to divide with overflow")) + } else { + if rhs.is_zero() { + crate::errors::div_zero!() + } + self.div_rem_unchecked(rhs).0 + } + } + } - crate::nightly::const_fn! { - #[inline] - pub const fn rem(self, rhs: Self) -> Self { - if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { - panic!(crate::errors::err_msg!("attempt to calculate remainder with overflow")) - } else { - if rhs.is_zero() { - crate::errors::rem_zero!() - } - self.div_rem_unchecked(rhs).1 - } - } - } - } - }; + crate::nightly::const_fn! { + #[inline] + pub const fn rem(self, rhs: Self) -> Self { + if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { + panic!(crate::errors::err_msg!("attempt to calculate remainder with overflow")) + } else { + if rhs.is_zero() { + crate::errors::rem_zero!() + } + self.div_rem_unchecked(rhs).1 + } + } + } + } + }; } -crate::macro_impl!(const_trait_fillers); \ No newline at end of file +crate::macro_impl!(const_trait_fillers); diff --git a/src/bint/consts.rs b/src/bint/consts.rs index c72df36..0bba14d 100644 --- a/src/bint/consts.rs +++ b/src/bint/consts.rs @@ -1,65 +1,65 @@ macro_rules! pos_const { - ($BUint: ident; $($name: ident $num: literal), *) => { - $( - #[doc = doc::consts::value_desc!($num)] - pub const $name: Self = Self::from_bits($BUint::$name); - )* - } + ($BUint: ident; $($name: ident $num: literal), *) => { + $( + #[doc = doc::consts::value_desc!($num)] + pub const $name: Self = Self::from_bits($BUint::$name); + )* + } } macro_rules! neg_const { - ($BUint: ident; $($name: ident $num: literal), *) => { - $( - #[doc = doc::consts::value_desc!("-" $num)] - pub const $name: Self = { - let mut u = $BUint::MAX; - u.digits[0] -= ($num - 1); - Self::from_bits(u) - }; - )* - } + ($BUint: ident; $($name: ident $num: literal), *) => { + $( + #[doc = doc::consts::value_desc!("-" $num)] + pub const $name: Self = { + let mut u = $BUint::MAX; + u.digits[0] -= ($num - 1); + Self::from_bits(u) + }; + )* + } } use crate::doc; use crate::ExpType; macro_rules! consts { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::consts::impl_desc!()] - impl $BInt { - #[doc = doc::consts::min!(I 512)] - pub const MIN: Self = { - let mut digits = [0; N]; - digits[N - 1] = 1 << ($Digit::BITS - 1); - Self::from_bits($BUint::from_digits(digits)) - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[doc = doc::consts::impl_desc!()] + impl $BInt { + #[doc = doc::consts::min!(I 512)] + pub const MIN: Self = { + let mut digits = [0; N]; + digits[N - 1] = 1 << ($Digit::BITS - 1); + Self::from_bits($BUint::from_digits(digits)) + }; - #[doc = doc::consts::max!(I 512)] - pub const MAX: Self = { - let mut digits = [$Digit::MAX; N]; - digits[N - 1] >>= 1; - Self::from_bits($BUint::from_digits(digits)) - }; + #[doc = doc::consts::max!(I 512)] + pub const MAX: Self = { + let mut digits = [$Digit::MAX; N]; + digits[N - 1] >>= 1; + Self::from_bits($BUint::from_digits(digits)) + }; - #[doc = doc::consts::bits!(I 512, 512)] - pub const BITS: ExpType = $BUint::::BITS; + #[doc = doc::consts::bits!(I 512, 512)] + pub const BITS: ExpType = $BUint::::BITS; - #[doc = doc::consts::bytes!(I 512, 512)] - pub const BYTES: ExpType = $BUint::::BYTES; + #[doc = doc::consts::bytes!(I 512, 512)] + pub const BYTES: ExpType = $BUint::::BYTES; - #[doc = doc::consts::zero!(I 512)] - pub const ZERO: Self = Self::from_bits($BUint::ZERO); + #[doc = doc::consts::zero!(I 512)] + pub const ZERO: Self = Self::from_bits($BUint::ZERO); - #[doc = doc::consts::one!(I 512)] - pub const ONE: Self = Self::from_bits($BUint::ONE); + #[doc = doc::consts::one!(I 512)] + pub const ONE: Self = Self::from_bits($BUint::ONE); - pos_const!($BUint; TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10); + pos_const!($BUint; TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10); - neg_const!($BUint; NEG_ONE 1, NEG_TWO 2, NEG_THREE 3, NEG_FOUR 4, NEG_FIVE 5, NEG_SIX 6, NEG_SEVEN 7, NEG_EIGHT 8, NEG_NINE 9, NEG_TEN 10); + neg_const!($BUint; NEG_ONE 1, NEG_TWO 2, NEG_THREE 3, NEG_FOUR 4, NEG_FIVE 5, NEG_SIX 6, NEG_SEVEN 7, NEG_EIGHT 8, NEG_NINE 9, NEG_TEN 10); - pub(crate) const N_MINUS_1: usize = N - 1; - } - } + pub(crate) const N_MINUS_1: usize = N - 1; + } + } } crate::macro_impl!(consts); diff --git a/src/bint/convert.rs b/src/bint/convert.rs index 57886f6..82933e4 100644 --- a/src/bint/convert.rs +++ b/src/bint/convert.rs @@ -1,195 +1,195 @@ macro_rules! from_int { - ($BInt: ident, $Digit: ident; $($int: tt),*) => { - $(impl_const! { - impl const From<$int> for $BInt { - #[inline] - fn from(int: $int) -> Self { - let mut out = if int.is_negative() { - !Self::ZERO - } else { - Self::ZERO - }; - let mut i = 0; - while i << crate::digit::$Digit::BIT_SHIFT < $int::BITS as usize { - let d = (int >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit; - out.bits.digits[i] = d; - i += 1; - } - out - } - } - })* - } + ($BInt: ident, $Digit: ident; $($int: tt),*) => { + $(impl_const! { + impl const From<$int> for $BInt { + #[inline] + fn from(int: $int) -> Self { + let mut out = if int.is_negative() { + !Self::ZERO + } else { + Self::ZERO + }; + let mut i = 0; + while i << crate::digit::$Digit::BIT_SHIFT < $int::BITS as usize { + let d = (int >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit; + out.bits.digits[i] = d; + i += 1; + } + out + } + } + })* + } } macro_rules! from_uint { - ($BInt: ident, $BUint: ident; $($from: tt), *) => { - $(impl_const! { - impl const From<$from> for $BInt { - #[inline] - fn from(int: $from) -> Self { - let out = Self::from_bits($BUint::from(int)); - out - } - } - })* - } + ($BInt: ident, $BUint: ident; $($from: tt), *) => { + $(impl_const! { + impl const From<$from> for $BInt { + #[inline] + fn from(int: $from) -> Self { + let out = Self::from_bits($BUint::from(int)); + out + } + } + })* + } } macro_rules! int_try_from_bint { - { $BInt: ident, $Digit: ident; $($int: ty), * } => { - $(crate::nightly::impl_const! { - impl const TryFrom<$BInt> for $int { - type Error = TryFromIntError; - - fn try_from(int: $BInt) -> Result<$int, Self::Error> { - let neg = int.is_negative(); - let (mut out, padding) = if neg { - (-1, $Digit::MAX) - } else { - (0, $Digit::MIN) - }; - let mut i = 0; - if $Digit::BITS > <$int>::BITS { - let small = int.bits.digits[i] as $int; - let trunc = small as $Digit; - if int.bits.digits[i] != trunc { - return Err(TryFromIntError(())); - } - out = small; - i = 1; - } else { - if neg { - loop { - let shift = i << digit::$Digit::BIT_SHIFT; - if i >= N || shift >= <$int>::BITS as usize { - break; - } - out &= !((!int.bits.digits[i]) as $int << shift); - i += 1; - } - } else { - loop { - let shift = i << digit::$Digit::BIT_SHIFT; - if i >= N || shift >= <$int>::BITS as usize { - break; - } - out |= int.bits.digits[i] as $int << shift; - i += 1; - } - } - } - - while i < N { - if int.bits.digits[i] != padding { - return Err(TryFromIntError(())); - } - i += 1; - } - - if out.is_negative() != neg { - return Err(TryFromIntError(())); - } - - Ok(out) - } - } - })* - }; + { $BInt: ident, $Digit: ident; $($int: ty), * } => { + $(crate::nightly::impl_const! { + impl const TryFrom<$BInt> for $int { + type Error = TryFromIntError; + + fn try_from(int: $BInt) -> Result<$int, Self::Error> { + let neg = int.is_negative(); + let (mut out, padding) = if neg { + (-1, $Digit::MAX) + } else { + (0, $Digit::MIN) + }; + let mut i = 0; + if $Digit::BITS > <$int>::BITS { + let small = int.bits.digits[i] as $int; + let trunc = small as $Digit; + if int.bits.digits[i] != trunc { + return Err(TryFromIntError(())); + } + out = small; + i = 1; + } else { + if neg { + loop { + let shift = i << digit::$Digit::BIT_SHIFT; + if i >= N || shift >= <$int>::BITS as usize { + break; + } + out &= !((!int.bits.digits[i]) as $int << shift); + i += 1; + } + } else { + loop { + let shift = i << digit::$Digit::BIT_SHIFT; + if i >= N || shift >= <$int>::BITS as usize { + break; + } + out |= int.bits.digits[i] as $int << shift; + i += 1; + } + } + } + + while i < N { + if int.bits.digits[i] != padding { + return Err(TryFromIntError(())); + } + i += 1; + } + + if out.is_negative() != neg { + return Err(TryFromIntError(())); + } + + Ok(out) + } + } + })* + }; } macro_rules! uint_try_from_bint { - ($BInt: ident; $($uint: ty), *) => { - $(crate::nightly::impl_const! { - impl const TryFrom<$BInt> for $uint { - type Error = TryFromIntError; - - #[inline] - fn try_from(int: $BInt) -> Result<$uint, Self::Error> { - if int.is_negative() { - Err(TryFromIntError(())) - } else { - <$uint>::try_from(int.bits) - } - } - } - })* - }; + ($BInt: ident; $($uint: ty), *) => { + $(crate::nightly::impl_const! { + impl const TryFrom<$BInt> for $uint { + type Error = TryFromIntError; + + #[inline] + fn try_from(int: $BInt) -> Result<$uint, Self::Error> { + if int.is_negative() { + Err(TryFromIntError(())) + } else { + <$uint>::try_from(int.bits) + } + } + } + })* + }; } use crate::cast::CastFrom; +use crate::digit; use crate::errors::{ParseIntError, TryFromIntError}; use crate::nightly::impl_const; use core::str::FromStr; -use crate::digit; macro_rules! convert { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl FromStr for $BInt { - type Err = ParseIntError; - - #[inline] - fn from_str(src: &str) -> Result { - Self::from_str_radix(src, 10) - } - } - - from_int!($BInt, $Digit; i8, i16, i32, i64, i128, isize); - - from_uint!($BInt, $BUint; u8, u16, u32, u64, u128, usize); - - impl_const! { - impl const From for $BInt { - #[inline] - fn from(small: bool) -> Self { - Self::cast_from(small) - } - } - } - - int_try_from_bint!($BInt, $Digit; i8, i16, i32, i64, i128, isize); - uint_try_from_bint!($BInt; u8, u16, u32, u64, u128, usize); - - impl_const! { - impl const TryFrom<$BUint> for $BInt { - type Error = TryFromIntError; - - #[inline] - fn try_from(u: $BUint) -> Result { - if u.leading_ones() != 0 { - Err(TryFromIntError(())) - } else { - Ok(Self::from_bits(u)) - } - } - } - } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::{self, types::itest}; - - #[cfg(not(test_int_bits = "64"))] - test::test_from! { - function: ::try_from, - from_types: (i8, i16, i32, i64, i128, u8, u16, u32, u64, bool, usize, isize) - } - - #[cfg(test_int_bits = "64")] - test::test_from! { - function: ::try_from, - from_types: (i8, i16, i32, i64, u8, u16, u32, bool, isize) - } - - test::test_into! { - function: ::try_into, - into_types: (u8, u16, u32, u64, usize, u128, i8, i16, i32, i64, i128, isize) - } - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + impl FromStr for $BInt { + type Err = ParseIntError; + + #[inline] + fn from_str(src: &str) -> Result { + Self::from_str_radix(src, 10) + } + } + + from_int!($BInt, $Digit; i8, i16, i32, i64, i128, isize); + + from_uint!($BInt, $BUint; u8, u16, u32, u64, u128, usize); + + impl_const! { + impl const From for $BInt { + #[inline] + fn from(small: bool) -> Self { + Self::cast_from(small) + } + } + } + + int_try_from_bint!($BInt, $Digit; i8, i16, i32, i64, i128, isize); + uint_try_from_bint!($BInt; u8, u16, u32, u64, u128, usize); + + impl_const! { + impl const TryFrom<$BUint> for $BInt { + type Error = TryFromIntError; + + #[inline] + fn try_from(u: $BUint) -> Result { + if u.leading_ones() != 0 { + Err(TryFromIntError(())) + } else { + Ok(Self::from_bits(u)) + } + } + } + } + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::{self, types::itest}; + + #[cfg(not(test_int_bits = "64"))] + test::test_from! { + function: ::try_from, + from_types: (i8, i16, i32, i64, i128, u8, u16, u32, u64, bool, usize, isize) + } + + #[cfg(test_int_bits = "64")] + test::test_from! { + function: ::try_from, + from_types: (i8, i16, i32, i64, u8, u16, u32, bool, isize) + } + + test::test_into! { + function: ::try_into, + into_types: (u8, u16, u32, u64, usize, u128, i8, i16, i32, i64, i128, isize) + } + } + } + }; } crate::macro_impl!(convert); diff --git a/src/bint/endian.rs b/src/bint/endian.rs index 935a396..2d8631a 100644 --- a/src/bint/endian.rs +++ b/src/bint/endian.rs @@ -3,225 +3,223 @@ use crate::doc; use core::mem::MaybeUninit; macro_rules! endian { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - macro_rules! set_digit { - ($out_digits: ident, $i: expr, $digit: expr, $is_negative: expr, $sign_bits: expr) => { - if $i == Self::N_MINUS_1 { - if ($digit as digit::$Digit::SignedDigit).is_negative() == $is_negative { - $out_digits[$i] = $digit; - } else { - return None; - } - } else if $i < N { - $out_digits[$i] = $digit; - } else if $digit != $sign_bits { - return None; - }; - }; - } - - #[doc = doc::endian::impl_desc!($BInt)] - impl $BInt { - #[doc = doc::endian::from_be!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn from_be(x: Self) -> Self { - Self::from_bits($BUint::from_be(x.bits)) - } - - #[doc = doc::endian::from_le!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn from_le(x: Self) -> Self { - Self::from_bits($BUint::from_le(x.bits)) - } - - #[doc = doc::endian::to_be!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_be(self) -> Self { - Self::from_be(self) - } - - #[doc = doc::endian::to_le!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_le(self) -> Self { - Self::from_le(self) - } - - crate::nightly::const_fns! { - /// Create an integer value from a slice of bytes in big endian. The value is wrapped in an [`Option`](https://doc.rust-lang.org/core/option/enum.Option.html) as the integer represented by the slice of bytes may represent an integer too large to be represented by the type. - /// - /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros or ones at the start so that it's length equals `Self::BYTES`. It is padded with ones if the bytes represent a negative integer, otherwise it is padded with zeros. - /// - /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless the bytes represent a non-negative integer and leading zeros from the slice can be removed until the length of the slice equals `Self::BYTES`, or if the bytes represent a negative integer and leading ones from the slice can be removed until the length of the slice equals `Self::BYTES`. - /// - /// For examples, see the - #[doc = concat!("[`from_be_slice`](crate::", stringify!($BUint), "::from_be_slice)")] - /// method documentation for - #[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] - #[must_use = doc::must_use_op!()] - pub const fn from_be_slice(slice: &[u8]) -> Option { - let len = slice.len(); - if len == 0 { - return Some(Self::ZERO); - } - let is_negative = (slice[0] as i8).is_negative(); - let sign_bits = if is_negative { $Digit::MAX } else { $Digit::MIN }; - let mut out_digits = if is_negative { [$Digit::MAX; N] } else { [0; N] }; - let slice_ptr = slice.as_ptr(); - let mut i = 0; - let exact = len >> digit::$Digit::BYTE_SHIFT; - while i < exact { - let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); - let ptr = uninit.as_mut_ptr() as *mut u8; - let digit_bytes = unsafe { - slice_ptr - .add(len - digit::$Digit::BYTES as usize - (i << digit::$Digit::BYTE_SHIFT)) - .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); - uninit.assume_init() - }; - let digit = $Digit::from_be_bytes(digit_bytes); - set_digit!(out_digits, i, digit, is_negative, sign_bits); - i += 1; - } - let rem = len & (digit::$Digit::BYTES as usize - 1); - if rem == 0 { - Some(Self::from_bits($BUint::from_digits(out_digits))) - } else { - let pad_byte = if is_negative { u8::MAX } else { 0 }; - let mut last_digit_bytes = [pad_byte; digit::$Digit::BYTES as usize]; - let mut j = 0; - while j < rem { - last_digit_bytes[digit::$Digit::BYTES as usize - rem + j] = slice[j]; - j += 1; - } - let digit = $Digit::from_be_bytes(last_digit_bytes); - set_digit!(out_digits, i, digit, is_negative, sign_bits); - Some(Self::from_bits($BUint::from_digits(out_digits))) - } - } - - /// Creates an integer value from a slice of bytes in little endian. The value is wrapped in an [`Option`](https://doc.rust-lang.org/core/option/enum.Option.html) as the bytes may represent an integer too large to be represented by the type. - /// - /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros or ones at the end so that it's length equals `Self::BYTES`. It is padded with ones if the bytes represent a negative integer, otherwise it is padded with zeros. - /// - /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless the bytes represent a non-negative integer and trailing zeros from the slice can be removed until the length of the slice equals `Self::BYTES`, or if the bytes represent a negative integer and trailing ones from the slice can be removed until the length of the slice equals `Self::BYTES`. - /// - /// For examples, see the - #[doc = concat!("[`from_le_slice`](crate::", stringify!($BUint), "::from_le_slice)")] - /// method documentation for - #[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] - #[must_use = doc::must_use_op!()] - pub const fn from_le_slice(slice: &[u8]) -> Option { - let len = slice.len(); - if len == 0 { - return Some(Self::ZERO); - } - let is_negative = (slice[len - 1] as i8).is_negative(); - let sign_bits = if is_negative { $Digit::MAX } else { $Digit::MIN }; - let mut out_digits = [sign_bits; N]; - let slice_ptr = slice.as_ptr(); - let mut i = 0; - let exact = len >> digit::$Digit::BYTE_SHIFT; - while i < exact { - let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); - let ptr = uninit.as_mut_ptr() as *mut u8; - let digit_bytes = unsafe { - slice_ptr - .add(i << digit::$Digit::BYTE_SHIFT) - .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); - uninit.assume_init() - }; - let digit = $Digit::from_le_bytes(digit_bytes); - set_digit!(out_digits, i, digit, is_negative, sign_bits); - i += 1; - } - if len & (digit::$Digit::BYTES as usize - 1) == 0 { - Some(Self::from_bits($BUint::from_digits(out_digits))) - } else { - let pad_byte = if is_negative { u8::MAX } else { 0 }; - let mut last_digit_bytes = [pad_byte; digit::$Digit::BYTES as usize]; - let addition = exact << digit::$Digit::BYTE_SHIFT; - let mut j = 0; - while j + addition < len { - last_digit_bytes[j] = slice[j + addition]; - j += 1; - } - let digit = $Digit::from_le_bytes(last_digit_bytes); - set_digit!(out_digits, i, digit, is_negative, sign_bits); - Some(Self::from_bits($BUint::from_digits(out_digits))) - } - } - } - - #[cfg(feature = "nightly")] - #[doc = doc::endian::to_be_bytes!(I)] - #[doc = doc::requires_feature!("nightly")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_be_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { - self.bits.to_be_bytes() - } - - #[cfg(feature = "nightly")] - #[doc = doc::endian::to_le_bytes!(I)] - #[doc = doc::requires_feature!("nightly")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_le_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { - self.bits.to_le_bytes() - } - - #[cfg(feature = "nightly")] - #[doc = doc::endian::to_ne_bytes!(I)] - #[doc = doc::requires_feature!("nightly")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_ne_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { - self.bits.to_ne_bytes() - } - - #[cfg(feature = "nightly")] - #[doc = doc::endian::from_be_bytes!(I)] - #[doc = doc::requires_feature!("nightly")] - #[must_use] - #[inline] - pub const fn from_be_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { - Self::from_bits($BUint::from_be_bytes(bytes)) - } - - #[cfg(feature = "nightly")] - #[doc = doc::endian::from_le_bytes!(I)] - #[doc = doc::requires_feature!("nightly")] - #[must_use] - #[inline] - pub const fn from_le_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { - Self::from_bits($BUint::from_le_bytes(bytes)) - } - - #[cfg(feature = "nightly")] - #[doc = doc::endian::from_ne_bytes!(I)] - #[doc = doc::requires_feature!("nightly")] - #[must_use] - #[inline] - pub const fn from_ne_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { - Self::from_bits($BUint::from_ne_bytes(bytes)) - } - } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::test_bignum; - use crate::test::types::itest; - - crate::int::endian::tests!($Digit; itest); - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + macro_rules! set_digit { + ($out_digits: ident, $i: expr, $digit: expr, $is_negative: expr, $sign_bits: expr) => { + if $i == Self::N_MINUS_1 { + if ($digit as digit::$Digit::SignedDigit).is_negative() == $is_negative { + $out_digits[$i] = $digit; + } else { + return None; + } + } else if $i < N { + $out_digits[$i] = $digit; + } else if $digit != $sign_bits { + return None; + }; + }; + } + + #[doc = doc::endian::impl_desc!($BInt)] + impl $BInt { + #[doc = doc::endian::from_be!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn from_be(x: Self) -> Self { + Self::from_bits($BUint::from_be(x.bits)) + } + + #[doc = doc::endian::from_le!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn from_le(x: Self) -> Self { + Self::from_bits($BUint::from_le(x.bits)) + } + + #[doc = doc::endian::to_be!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_be(self) -> Self { + Self::from_be(self) + } + + #[doc = doc::endian::to_le!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_le(self) -> Self { + Self::from_le(self) + } + + /// Create an integer value from a slice of bytes in big endian. The value is wrapped in an [`Option`](https://doc.rust-lang.org/core/option/enum.Option.html) as the integer represented by the slice of bytes may represent an integer too large to be represented by the type. + /// + /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros or ones at the start so that it's length equals `Self::BYTES`. It is padded with ones if the bytes represent a negative integer, otherwise it is padded with zeros. + /// + /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless the bytes represent a non-negative integer and leading zeros from the slice can be removed until the length of the slice equals `Self::BYTES`, or if the bytes represent a negative integer and leading ones from the slice can be removed until the length of the slice equals `Self::BYTES`. + /// + /// For examples, see the + #[doc = concat!("[`from_be_slice`](crate::", stringify!($BUint), "::from_be_slice)")] + /// method documentation for + #[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] + #[must_use = doc::must_use_op!()] + pub const fn from_be_slice(slice: &[u8]) -> Option { + let len = slice.len(); + if len == 0 { + return Some(Self::ZERO); + } + let is_negative = (slice[0] as i8).is_negative(); + let sign_bits = if is_negative { $Digit::MAX } else { $Digit::MIN }; + let mut out_digits = if is_negative { [$Digit::MAX; N] } else { [0; N] }; + let slice_ptr = slice.as_ptr(); + let mut i = 0; + let exact = len >> digit::$Digit::BYTE_SHIFT; + while i < exact { + let uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); + let ptr = uninit.as_ptr().cast_mut() as *mut u8; + let digit_bytes = unsafe { + slice_ptr + .add(len - digit::$Digit::BYTES as usize - (i << digit::$Digit::BYTE_SHIFT)) + .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); + uninit.assume_init() + }; + let digit = $Digit::from_be_bytes(digit_bytes); + set_digit!(out_digits, i, digit, is_negative, sign_bits); + i += 1; + } + let rem = len & (digit::$Digit::BYTES as usize - 1); + if rem == 0 { + Some(Self::from_bits($BUint::from_digits(out_digits))) + } else { + let pad_byte = if is_negative { u8::MAX } else { 0 }; + let mut last_digit_bytes = [pad_byte; digit::$Digit::BYTES as usize]; + let mut j = 0; + while j < rem { + last_digit_bytes[digit::$Digit::BYTES as usize - rem + j] = slice[j]; + j += 1; + } + let digit = $Digit::from_be_bytes(last_digit_bytes); + set_digit!(out_digits, i, digit, is_negative, sign_bits); + Some(Self::from_bits($BUint::from_digits(out_digits))) + } + } + + /// Creates an integer value from a slice of bytes in little endian. The value is wrapped in an [`Option`](https://doc.rust-lang.org/core/option/enum.Option.html) as the bytes may represent an integer too large to be represented by the type. + /// + /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros or ones at the end so that it's length equals `Self::BYTES`. It is padded with ones if the bytes represent a negative integer, otherwise it is padded with zeros. + /// + /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless the bytes represent a non-negative integer and trailing zeros from the slice can be removed until the length of the slice equals `Self::BYTES`, or if the bytes represent a negative integer and trailing ones from the slice can be removed until the length of the slice equals `Self::BYTES`. + /// + /// For examples, see the + #[doc = concat!("[`from_le_slice`](crate::", stringify!($BUint), "::from_le_slice)")] + /// method documentation for + #[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] + #[must_use = doc::must_use_op!()] + pub const fn from_le_slice(slice: &[u8]) -> Option { + let len = slice.len(); + if len == 0 { + return Some(Self::ZERO); + } + let is_negative = (slice[len - 1] as i8).is_negative(); + let sign_bits = if is_negative { $Digit::MAX } else { $Digit::MIN }; + let mut out_digits = [sign_bits; N]; + let slice_ptr = slice.as_ptr(); + let mut i = 0; + let exact = len >> digit::$Digit::BYTE_SHIFT; + while i < exact { + let uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); + let ptr = uninit.as_ptr().cast_mut() as *mut u8; // TODO: can change to as_mut_ptr() when const_mut_refs is stabilised + let digit_bytes = unsafe { + slice_ptr + .add(i << digit::$Digit::BYTE_SHIFT) + .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); + uninit.assume_init() + }; + let digit = $Digit::from_le_bytes(digit_bytes); + set_digit!(out_digits, i, digit, is_negative, sign_bits); + i += 1; + } + if len & (digit::$Digit::BYTES as usize - 1) == 0 { + Some(Self::from_bits($BUint::from_digits(out_digits))) + } else { + let pad_byte = if is_negative { u8::MAX } else { 0 }; + let mut last_digit_bytes = [pad_byte; digit::$Digit::BYTES as usize]; + let addition = exact << digit::$Digit::BYTE_SHIFT; + let mut j = 0; + while j + addition < len { + last_digit_bytes[j] = slice[j + addition]; + j += 1; + } + let digit = $Digit::from_le_bytes(last_digit_bytes); + set_digit!(out_digits, i, digit, is_negative, sign_bits); + Some(Self::from_bits($BUint::from_digits(out_digits))) + } + } + + #[cfg(feature = "nightly")] + #[doc = doc::endian::to_be_bytes!(I)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_be_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { + self.bits.to_be_bytes() + } + + #[cfg(feature = "nightly")] + #[doc = doc::endian::to_le_bytes!(I)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_le_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { + self.bits.to_le_bytes() + } + + #[cfg(feature = "nightly")] + #[doc = doc::endian::to_ne_bytes!(I)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_ne_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { + self.bits.to_ne_bytes() + } + + #[cfg(feature = "nightly")] + #[doc = doc::endian::from_be_bytes!(I)] + #[doc = doc::requires_feature!("nightly")] + #[must_use] + #[inline] + pub const fn from_be_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { + Self::from_bits($BUint::from_be_bytes(bytes)) + } + + #[cfg(feature = "nightly")] + #[doc = doc::endian::from_le_bytes!(I)] + #[doc = doc::requires_feature!("nightly")] + #[must_use] + #[inline] + pub const fn from_le_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { + Self::from_bits($BUint::from_le_bytes(bytes)) + } + + #[cfg(feature = "nightly")] + #[doc = doc::endian::from_ne_bytes!(I)] + #[doc = doc::requires_feature!("nightly")] + #[must_use] + #[inline] + pub const fn from_ne_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { + Self::from_bits($BUint::from_ne_bytes(bytes)) + } + } + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::test_bignum; + use crate::test::types::itest; + + crate::int::endian::tests!($Digit; itest); + } + } + }; } crate::macro_impl!(endian); diff --git a/src/bint/mod.rs b/src/bint/mod.rs index 14711a8..bc65db9 100644 --- a/src/bint/mod.rs +++ b/src/bint/mod.rs @@ -1,21 +1,21 @@ macro_rules! ilog { - ($method: ident $(, $base: ident : $ty: ty)?) => { - crate::nightly::const_fn! { - #[doc = doc::$method!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn $method(self, $($base : $ty),*) -> ExpType { - if self.is_negative() { - #[cfg(debug_assertions)] - panic!(errors::err_msg!("attempt to calculate ilog of negative number")); - #[cfg(not(debug_assertions))] - 0 - } else { - self.bits.$method($($base.bits)?) - } - } - } - } + ($method: ident $(, $base: ident : $ty: ty)?) => { + crate::nightly::const_fn! { + #[doc = doc::$method!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn $method(self, $($base : $ty),*) -> ExpType { + if self.is_negative() { + #[cfg(debug_assertions)] + panic!(errors::err_msg!("attempt to calculate ilog of negative number")); + #[cfg(not(debug_assertions))] + 0 + } else { + self.bits.$method($($base.bits)?) + } + } + } + } } #[cfg(debug_assertions)] @@ -32,441 +32,443 @@ use core::default::Default; use core::iter::{Iterator, Product, Sum}; +#[cfg(feature = "arbitrary")] +use arbitrary::Arbitrary; + macro_rules! mod_impl { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - /// Big signed integer type, of fixed size which must be known at compile time. - /// - /// Digits of the underlying - #[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ")")] - /// are stored in little endian (least significant digit first). This integer type aims to exactly replicate the behaviours of Rust's built-in signed integer types: [`i8`], [`i16`], [`i32`], [`i64`], [`i128`] and [`isize`]. The const generic parameter `N` is the number of digits that are stored in the underlying - #[doc = concat!("[`", stringify!($BUint), "`].")] - /// - #[doc = doc::arithmetic_doc!($BInt)] - - // Clippy: we can allow derivation of `Hash` and manual implementation of `PartialEq` as the derived `PartialEq` would be the same except we make our implementation const. - #[allow(clippy::derive_hash_xor_eq)] - #[derive(Clone, Copy, Hash)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] - pub struct $BInt { - pub(crate) bits: $BUint, - } - - impl $BInt { - #[doc = doc::count_ones!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn count_ones(self) -> ExpType { - self.bits.count_ones() - } - - #[doc = doc::count_zeros!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn count_zeros(self) -> ExpType { - self.bits.count_zeros() - } - - #[doc = doc::leading_zeros!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn leading_zeros(self) -> ExpType { - self.bits.leading_zeros() - } - - #[doc = doc::trailing_zeros!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn trailing_zeros(self) -> ExpType { - self.bits.trailing_zeros() - } - - #[doc = doc::leading_ones!(I 256, NEG_ONE)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn leading_ones(self) -> ExpType { - self.bits.leading_ones() - } - - #[doc = doc::trailing_ones!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn trailing_ones(self) -> ExpType { - self.bits.trailing_ones() - } - - crate::nightly::const_fns! { - #[doc = doc::rotate_left!(I 256, "i")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn rotate_left(self, n: ExpType) -> Self { - Self::from_bits(self.bits.rotate_left(n)) - } - - #[doc = doc::rotate_right!(I 256, "i")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn rotate_right(self, n: ExpType) -> Self { - Self::from_bits(self.bits.rotate_right(n)) - } - } - - #[doc = doc::swap_bytes!(I 256, "i")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn swap_bytes(self) -> Self { - Self::from_bits(self.bits.swap_bytes()) - } - - #[doc = doc::reverse_bits!(I 256, "i")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn reverse_bits(self) -> Self { - Self::from_bits(self.bits.reverse_bits()) - } - - #[doc = doc::unsigned_abs!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn unsigned_abs(self) -> $BUint { - if self.is_negative() { - self.wrapping_neg().bits - } else { - self.bits - } - } - - #[doc = doc::pow!(I 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn pow(self, exp: ExpType) -> Self { - #[cfg(debug_assertions)] - return option_expect!(self.checked_pow(exp), errors::err_msg!("attempt to calculate power with overflow")); - - #[cfg(not(debug_assertions))] - self.wrapping_pow(exp) - } - - crate::nightly::const_fns! { - #[doc = doc::div_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn div_euclid(self, rhs: Self) -> Self { - assert!(self.ne(&Self::MIN) || rhs.ne(&Self::NEG_ONE), errors::err_msg!("attempt to divide with overflow")); - self.wrapping_div_euclid(rhs) - } - - #[doc = doc::rem_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn rem_euclid(self, rhs: Self) -> Self { - assert!(self.ne(&Self::MIN) || rhs.ne(&Self::NEG_ONE), errors::err_msg!("attempt to calculate remainder with overflow")); - self.wrapping_rem_euclid(rhs) - } - } - - #[doc = doc::abs!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn abs(self) -> Self { - #[cfg(debug_assertions)] - return option_expect!(self.checked_abs(), errors::err_msg!("attempt to negate with overflow")); - - #[cfg(not(debug_assertions))] - match self.checked_abs() { - Some(int) => int, - None => Self::MIN, - } - } - - #[doc = doc::signum!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn signum(self) -> Self { - if self.is_negative() { - Self::NEG_ONE - } else if self.is_zero() { - Self::ZERO - } else { - Self::ONE - } - } - - #[doc = doc::is_positive!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn is_positive(self) -> bool { - let signed_digit = self.signed_digit(); - signed_digit.is_positive() || (signed_digit == 0 && !self.bits.is_zero()) - } - - #[doc = doc::is_negative!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn is_negative(self) -> bool { - self.signed_digit().is_negative() - } - - #[doc = doc::doc_comment! { - I 256, - "Returns `true` if and only if `self == 2^k` for some integer `k`.", - - "let n = " stringify!(I256) "::from(1i16 << 12);\n" - "assert!(n.is_power_of_two());\n" - "let m = " stringify!(I256) "::from(90i8);\n" - "assert!(!m.is_power_of_two());\n" - "assert!(!((-n).is_power_of_two()));" - }] - #[must_use] - #[inline] - pub const fn is_power_of_two(self) -> bool { - !self.is_negative() &&self.bits.is_power_of_two() - } - - ilog!(ilog, base: Self); - ilog!(ilog2); - ilog!(ilog10); - - #[doc = doc::abs_diff!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn abs_diff(self, other: Self) -> $BUint { - if self.lt(other) { - other.wrapping_sub(self).to_bits() - } else { - self.wrapping_sub(other).to_bits() - } - } - - crate::nightly::const_fns! { - #[doc = doc::next_multiple_of!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn next_multiple_of(self, rhs: Self) -> Self { - let rem = self.wrapping_rem_euclid(rhs); - if rem.is_zero() { - return self; - } - if rem.is_negative() == rhs.is_negative() { - self.add(rhs.sub(rem)) - } else { - self.sub(rem) - } - } - - #[doc = doc::div_floor!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn div_floor(self, rhs: Self) -> Self { - if rhs.is_zero() { - errors::div_zero!(); - } - let (div, rem) = self.div_rem_unchecked(rhs); - if rem.is_zero() || self.is_negative() == rhs.is_negative() { - div - } else { - div.sub(Self::ONE) - } - } - - #[doc = doc::div_ceil!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn div_ceil(self, rhs: Self) -> Self { - if rhs.is_zero() { - errors::div_zero!(); - } - let (div, rem) = self.div_rem_unchecked(rhs); - if rem.is_zero() || self.is_negative() != rhs.is_negative() { - div - } else { - div.add(Self::ONE) - } - } - } - } - - impl $BInt { - #[doc = doc::bits!(I 256)] - #[must_use] - #[inline] - pub const fn bits(&self) -> ExpType { - self.bits.bits() - } - - #[doc = doc::bit!(I 256)] - #[must_use] - #[inline] - pub const fn bit(&self, b: ExpType) -> bool { - self.bits.bit(b) - } - - #[inline(always)] - pub(crate) const fn signed_digit(&self) -> digit::$Digit::SignedDigit { - self.bits.digits[N - 1] as _ - } - - #[doc = doc::is_zero!(I 256)] - #[must_use] - #[inline] - pub const fn is_zero(&self) -> bool { - self.bits.is_zero() - } - - #[doc = doc::is_one!(I 256)] - #[must_use] - #[inline] - pub const fn is_one(&self) -> bool { - self.bits.is_one() - } - - /// Creates a signed integer with `bits` as its underlying representation in two's complement. - /// - /// This method is faster for casting from a - #[doc = concat!("[`", stringify!($BUint), "`]")] - /// to a - #[doc = concat!("[`", stringify!($BInt), "`]")] - /// of the same size than using the `As` trait. - #[must_use] - #[inline(always)] - pub const fn from_bits(bits: $BUint) -> Self { - Self { bits } - } - - /// This simply returns the underlying representation of the integer in two's complement, as an unsigned integer. - /// - /// This method is faster for casting from a - #[doc = concat!("[`", stringify!($BInt), "`]")] - /// to a - #[doc = concat!("[`", stringify!($BUint), "`]")] - /// of the same size than using the `As` trait. - #[must_use] - #[inline(always)] - pub const fn to_bits(self) -> $BUint { - self.bits - } - - #[inline] - pub(crate) const fn to_exp_type(self) -> Option { - if self.is_negative() { - None - } else { - self.bits.to_exp_type() - } - } - } - - impl Default for $BInt { - #[doc = doc::default!()] - #[inline] - fn default() -> Self { - Self::ZERO - } - } - - impl Product for $BInt { - #[inline] - fn product>(iter: I) -> Self { - iter.fold(Self::ONE, |a, b| a * b) - } - } - - impl<'a, const N: usize> Product<&'a Self> for $BInt { - #[inline] - fn product>(iter: I) -> Self { - iter.fold(Self::ONE, |a, b| a * b) - } - } - - impl Sum for $BInt { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::ZERO, |a, b| a + b) - } - } - - impl<'a, const N: usize> Sum<&'a Self> for $BInt { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::ZERO, |a, b| a + b) - } - } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::{ - debug_skip, test_bignum, - types::itest, - }; - use crate::test::types::big_types::$Digit::*; - - crate::int::tests!(itest); - - test_bignum! { - function: ::unsigned_abs(a: itest), - cases: [ - (itest::MIN), - (0 as itest) - ] - } - test_bignum! { - function: ::abs(a: itest), - skip: debug_skip!(a == itest::MIN) - } - test_bignum! { - function: ::signum(a: itest) - } - test_bignum! { - function: ::is_positive(a: itest) - } - test_bignum! { - function: ::is_negative(a: itest) - } - - #[test] - fn bit() { - let i = ITEST::from(0b1001010100101010101i64); - assert!(i.bit(2)); - assert!(!i.bit(3)); - assert!(i.bit(8)); - assert!(!i.bit(9)); - assert!(i.bit(i.bits() - 1)); - } - - #[test] - fn is_zero() { - assert!(ITEST::ZERO.is_zero()); - assert!(!ITEST::MAX.is_zero()); - assert!(!ITEST::ONE.is_zero()); - } - - #[test] - fn is_one() { - assert!(ITEST::ONE.is_one()); - assert!(!ITEST::MAX.is_one()); - assert!(!ITEST::ZERO.is_one()); - } - - #[test] - fn bits() { - let u = ITEST::from(0b11101001010100101010101i32); - assert_eq!(u.bits(), 23); - } - - #[test] - fn default() { - assert_eq!(ITEST::default(), itest::default().into()); - } - - #[test] - fn is_power_of_two() { - assert!(!ITEST::from(-94956729465i64).is_power_of_two()); - assert!(!ITEST::from(79458945i32).is_power_of_two()); - assert!(ITEST::from(1i32 << 17).is_power_of_two()); - } - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + /// Big signed integer type, of fixed size which must be known at compile time. + /// + /// Digits of the underlying + #[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ")")] + /// are stored in little endian (least significant digit first). This integer type aims to exactly replicate the behaviours of Rust's built-in signed integer types: [`i8`], [`i16`], [`i32`], [`i64`], [`i128`] and [`isize`]. The const generic parameter `N` is the number of digits that are stored in the underlying + #[doc = concat!("[`", stringify!($BUint), "`].")] + /// + #[doc = doc::arithmetic_doc!($BInt)] + + // Clippy: we can allow derivation of `Hash` and manual implementation of `PartialEq` as the derived `PartialEq` would be the same except we make our implementation const. + #[allow(clippy::derived_hash_with_manual_eq)] + #[derive(Clone, Copy, Hash)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] + pub struct $BInt { + pub(crate) bits: $BUint, + } + + impl $BInt { + #[doc = doc::count_ones!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn count_ones(self) -> ExpType { + self.bits.count_ones() + } + + #[doc = doc::count_zeros!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn count_zeros(self) -> ExpType { + self.bits.count_zeros() + } + + #[doc = doc::leading_zeros!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn leading_zeros(self) -> ExpType { + self.bits.leading_zeros() + } + + #[doc = doc::trailing_zeros!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn trailing_zeros(self) -> ExpType { + self.bits.trailing_zeros() + } + + #[doc = doc::leading_ones!(I 256, NEG_ONE)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn leading_ones(self) -> ExpType { + self.bits.leading_ones() + } + + #[doc = doc::trailing_ones!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn trailing_ones(self) -> ExpType { + self.bits.trailing_ones() + } + + #[doc = doc::rotate_left!(I 256, "i")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn rotate_left(self, n: ExpType) -> Self { + Self::from_bits(self.bits.rotate_left(n)) + } + + #[doc = doc::rotate_right!(I 256, "i")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn rotate_right(self, n: ExpType) -> Self { + Self::from_bits(self.bits.rotate_right(n)) + } + + #[doc = doc::swap_bytes!(I 256, "i")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn swap_bytes(self) -> Self { + Self::from_bits(self.bits.swap_bytes()) + } + + #[doc = doc::reverse_bits!(I 256, "i")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn reverse_bits(self) -> Self { + Self::from_bits(self.bits.reverse_bits()) + } + + #[doc = doc::unsigned_abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn unsigned_abs(self) -> $BUint { + if self.is_negative() { + self.wrapping_neg().bits + } else { + self.bits + } + } + + #[doc = doc::pow!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn pow(self, exp: ExpType) -> Self { + #[cfg(debug_assertions)] + return option_expect!(self.checked_pow(exp), errors::err_msg!("attempt to calculate power with overflow")); + + #[cfg(not(debug_assertions))] + self.wrapping_pow(exp) + } + + crate::nightly::const_fns! { + #[doc = doc::div_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn div_euclid(self, rhs: Self) -> Self { + assert!(self.ne(&Self::MIN) || rhs.ne(&Self::NEG_ONE), errors::err_msg!("attempt to divide with overflow")); + self.wrapping_div_euclid(rhs) + } + + #[doc = doc::rem_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn rem_euclid(self, rhs: Self) -> Self { + assert!(self.ne(&Self::MIN) || rhs.ne(&Self::NEG_ONE), errors::err_msg!("attempt to calculate remainder with overflow")); + self.wrapping_rem_euclid(rhs) + } + } + + #[doc = doc::abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn abs(self) -> Self { + #[cfg(debug_assertions)] + return option_expect!(self.checked_abs(), errors::err_msg!("attempt to negate with overflow")); + + #[cfg(not(debug_assertions))] + match self.checked_abs() { + Some(int) => int, + None => Self::MIN, + } + } + + #[doc = doc::signum!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn signum(self) -> Self { + if self.is_negative() { + Self::NEG_ONE + } else if self.is_zero() { + Self::ZERO + } else { + Self::ONE + } + } + + #[doc = doc::is_positive!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn is_positive(self) -> bool { + let signed_digit = self.signed_digit(); + signed_digit.is_positive() || (signed_digit == 0 && !self.bits.is_zero()) + } + + #[doc = doc::is_negative!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn is_negative(self) -> bool { + self.signed_digit().is_negative() + } + + #[doc = doc::doc_comment! { + I 256, + "Returns `true` if and only if `self == 2^k` for some integer `k`.", + + "let n = " stringify!(I256) "::from(1i16 << 12);\n" + "assert!(n.is_power_of_two());\n" + "let m = " stringify!(I256) "::from(90i8);\n" + "assert!(!m.is_power_of_two());\n" + "assert!(!((-n).is_power_of_two()));" + }] + #[must_use] + #[inline] + pub const fn is_power_of_two(self) -> bool { + !self.is_negative() &&self.bits.is_power_of_two() + } + + ilog!(ilog, base: Self); + ilog!(ilog2); + ilog!(ilog10); + + #[doc = doc::abs_diff!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn abs_diff(self, other: Self) -> $BUint { + if self.lt(other) { + other.wrapping_sub(self).to_bits() + } else { + self.wrapping_sub(other).to_bits() + } + } + + crate::nightly::const_fns! { + #[doc = doc::next_multiple_of!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn next_multiple_of(self, rhs: Self) -> Self { + let rem = self.wrapping_rem_euclid(rhs); + if rem.is_zero() { + return self; + } + if rem.is_negative() == rhs.is_negative() { + self.add(rhs.sub(rem)) + } else { + self.sub(rem) + } + } + + #[doc = doc::div_floor!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn div_floor(self, rhs: Self) -> Self { + if rhs.is_zero() { + errors::div_zero!(); + } + let (div, rem) = self.div_rem_unchecked(rhs); + if rem.is_zero() || self.is_negative() == rhs.is_negative() { + div + } else { + div.sub(Self::ONE) + } + } + + #[doc = doc::div_ceil!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn div_ceil(self, rhs: Self) -> Self { + if rhs.is_zero() { + errors::div_zero!(); + } + let (div, rem) = self.div_rem_unchecked(rhs); + if rem.is_zero() || self.is_negative() != rhs.is_negative() { + div + } else { + div.add(Self::ONE) + } + } + } + } + + impl $BInt { + #[doc = doc::bits!(I 256)] + #[must_use] + #[inline] + pub const fn bits(&self) -> ExpType { + self.bits.bits() + } + + #[doc = doc::bit!(I 256)] + #[must_use] + #[inline] + pub const fn bit(&self, b: ExpType) -> bool { + self.bits.bit(b) + } + + #[inline(always)] + pub(crate) const fn signed_digit(&self) -> digit::$Digit::SignedDigit { + self.bits.digits[N - 1] as _ + } + + #[doc = doc::is_zero!(I 256)] + #[must_use] + #[inline] + pub const fn is_zero(&self) -> bool { + self.bits.is_zero() + } + + #[doc = doc::is_one!(I 256)] + #[must_use] + #[inline] + pub const fn is_one(&self) -> bool { + self.bits.is_one() + } + + /// Creates a signed integer with `bits` as its underlying representation in two's complement. + /// + /// This method is faster for casting from a + #[doc = concat!("[`", stringify!($BUint), "`]")] + /// to a + #[doc = concat!("[`", stringify!($BInt), "`]")] + /// of the same size than using the `As` trait. + #[must_use] + #[inline(always)] + pub const fn from_bits(bits: $BUint) -> Self { + Self { bits } + } + + /// This simply returns the underlying representation of the integer in two's complement, as an unsigned integer. + /// + /// This method is faster for casting from a + #[doc = concat!("[`", stringify!($BInt), "`]")] + /// to a + #[doc = concat!("[`", stringify!($BUint), "`]")] + /// of the same size than using the `As` trait. + #[must_use] + #[inline(always)] + pub const fn to_bits(self) -> $BUint { + self.bits + } + + #[inline] + pub(crate) const fn to_exp_type(self) -> Option { + if self.is_negative() { + None + } else { + self.bits.to_exp_type() + } + } + } + + impl Default for $BInt { + #[doc = doc::default!()] + #[inline] + fn default() -> Self { + Self::ZERO + } + } + + impl Product for $BInt { + #[inline] + fn product>(iter: I) -> Self { + iter.fold(Self::ONE, |a, b| a * b) + } + } + + impl<'a, const N: usize> Product<&'a Self> for $BInt { + #[inline] + fn product>(iter: I) -> Self { + iter.fold(Self::ONE, |a, b| a * b) + } + } + + impl Sum for $BInt { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |a, b| a + b) + } + } + + impl<'a, const N: usize> Sum<&'a Self> for $BInt { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |a, b| a + b) + } + } + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::{ + debug_skip, test_bignum, + types::itest, + }; + use crate::test::types::big_types::$Digit::*; + + crate::int::tests!(itest); + + test_bignum! { + function: ::unsigned_abs(a: itest), + cases: [ + (itest::MIN), + (0 as itest) + ] + } + test_bignum! { + function: ::abs(a: itest), + skip: debug_skip!(a == itest::MIN) + } + test_bignum! { + function: ::signum(a: itest) + } + test_bignum! { + function: ::is_positive(a: itest) + } + test_bignum! { + function: ::is_negative(a: itest) + } + + #[test] + fn bit() { + let i = ITEST::from(0b1001010100101010101i64); + assert!(i.bit(2)); + assert!(!i.bit(3)); + assert!(i.bit(8)); + assert!(!i.bit(9)); + assert!(i.bit(i.bits() - 1)); + } + + #[test] + fn is_zero() { + assert!(ITEST::ZERO.is_zero()); + assert!(!ITEST::MAX.is_zero()); + assert!(!ITEST::ONE.is_zero()); + } + + #[test] + fn is_one() { + assert!(ITEST::ONE.is_one()); + assert!(!ITEST::MAX.is_one()); + assert!(!ITEST::ZERO.is_one()); + } + + #[test] + fn bits() { + let u = ITEST::from(0b11101001010100101010101i32); + assert_eq!(u.bits(), 23); + } + + #[test] + fn default() { + assert_eq!(ITEST::default(), itest::default().into()); + } + + #[test] + fn is_power_of_two() { + assert!(!ITEST::from(-94956729465i64).is_power_of_two()); + assert!(!ITEST::from(79458945i32).is_power_of_two()); + assert!(ITEST::from(1i32 << 17).is_power_of_two()); + } + } + } + }; } crate::macro_impl!(mod_impl); diff --git a/src/bint/numtraits.rs b/src/bint/numtraits.rs index 0e26af6..7847bf7 100644 --- a/src/bint/numtraits.rs +++ b/src/bint/numtraits.rs @@ -82,78 +82,79 @@ macro_rules! from_float { } macro_rules! to_uint { - { $($name: ident -> $uint: ty), * } => { - $( - #[inline] - fn $name(&self) -> Option<$uint> { - if self.is_negative() { - None - } else { - self.bits.$name() - } - } - )* - }; + { $($name: ident -> $uint: ty), * } => { + $( + #[inline] + fn $name(&self) -> Option<$uint> { + if self.is_negative() { + None + } else { + self.bits.$name() + } + } + )* + }; } macro_rules! to_int { - { $Digit: ident; $($name: ident -> $int: ty), * } => { - $( - fn $name(&self) -> Option<$int> { - let neg = self.is_negative(); - let (mut out, padding) = if neg { - (-1, $Digit::MAX) - } else { - (0, $Digit::MIN) - }; - let mut i = 0; - if $Digit::BITS > <$int>::BITS { - let small = self.bits.digits[i] as $int; - let trunc = small as $Digit; - if self.bits.digits[i] != trunc { - return None; - } - out = small; - i = 1; - } else { - if neg { - loop { - let shift = i << digit::$Digit::BIT_SHIFT; - if i >= N || shift >= <$int>::BITS as usize { - break; - } - out &= !((!self.bits.digits[i]) as $int << shift); - i += 1; - } - } else { - loop { - let shift = i << digit::$Digit::BIT_SHIFT; - if i >= N || shift >= <$int>::BITS as usize { - break; - } - out |= self.bits.digits[i] as $int << shift; - i += 1; - } - } - } - - while i < N { - if self.bits.digits[i] != padding { - return None; - } - i += 1; - } - - if out.is_negative() != neg { - return None; - } - - Some(out) - } - )* - }; + { $Digit: ident; $($name: ident -> $int: ty), * } => { + $( + fn $name(&self) -> Option<$int> { + let neg = self.is_negative(); + let (mut out, padding) = if neg { + (-1, $Digit::MAX) + } else { + (0, $Digit::MIN) + }; + let mut i = 0; + if $Digit::BITS > <$int>::BITS { + let small = self.bits.digits[i] as $int; + let trunc = small as $Digit; + if self.bits.digits[i] != trunc { + return None; + } + out = small; + i = 1; + } else { + if neg { + loop { + let shift = i << digit::$Digit::BIT_SHIFT; + if i >= N || shift >= <$int>::BITS as usize { + break; + } + out &= !((!self.bits.digits[i]) as $int << shift); + i += 1; + } + } else { + loop { + let shift = i << digit::$Digit::BIT_SHIFT; + if i >= N || shift >= <$int>::BITS as usize { + break; + } + out |= self.bits.digits[i] as $int << shift; + i += 1; + } + } + } + + while i < N { + if self.bits.digits[i] != padding { + return None; + } + i += 1; + } + + if out.is_negative() != neg { + return None; + } + + Some(out) + } + )* + }; } +use crate::digit; use crate::errors; use crate::ExpType; use num_integer::{Integer, Roots}; @@ -163,230 +164,229 @@ use num_traits::{ Saturating, SaturatingAdd, SaturatingMul, SaturatingSub, Signed, ToPrimitive, WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, Zero, }; -use crate::digit; use crate::cast::CastFrom; use crate::int::numtraits::num_trait_impl; macro_rules! numtraits { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - crate::int::numtraits::impls!($BInt, $BUint, $BInt); - - impl FromPrimitive for $BInt { - from_uint!($Digit; u8, from_u8); - from_uint!($Digit; u16, from_u16); - from_uint!($Digit; u32, from_u32); - from_uint!($Digit; u64, from_u64); - from_uint!($Digit; u128, from_u128); - from_uint!($Digit; usize, from_usize); - from_int!($BUint, $Digit; i8, from_i8); - from_int!($BUint, $Digit; i16, from_i16); - from_int!($BUint, $Digit; i32, from_i32); - from_int!($BUint, $Digit; i64, from_i64); - from_int!($BUint, $Digit; i128, from_i128); - from_int!($BUint, $Digit; isize, from_isize); - - from_float!($BUint; from_f32, f32); - from_float!($BUint; from_f64, f64); - } - - //crate::nightly::impl_const! { - impl Integer for $BInt { - #[inline] - fn div_floor(&self, other: &Self) -> Self { - *self / *other - } - - #[inline] - fn mod_floor(&self, other: &Self) -> Self { - *self % *other - } - - #[inline] - fn gcd(&self, other: &Self) -> Self { - let gcd = self.unsigned_abs().gcd(&other.unsigned_abs()); - let out = Self::from_bits(gcd); - if out == Self::MIN { - panic!("{}", errors::err_msg!("gcd of is too large")); - } - out.abs() - } - - #[inline] - fn lcm(&self, other: &Self) -> Self { - self.div_floor(&self.gcd(other)) * *other - } - - #[inline] - fn divides(&self, other: &Self) -> bool { - self.is_multiple_of(other) - } - - #[inline] - fn is_multiple_of(&self, other: &Self) -> bool { - self.mod_floor(other).is_zero() - } - - #[inline] - fn is_even(&self) -> bool { - self.bits.is_even() - } - - #[inline] - fn is_odd(&self) -> bool { - self.bits.is_odd() - } - - #[inline] - fn div_rem(&self, other: &Self) -> (Self, Self) { - (self.div_floor(other), self.mod_floor(other)) - } - } - //} - - //crate::nightly::impl_const! { - impl PrimInt for $BInt { - crate::int::numtraits::prim_int_methods!(); - - #[inline] - fn signed_shl(self, n: u32) -> Self { - self << n - } - - #[inline] - fn signed_shr(self, n: u32) -> Self { - self >> n - } - - #[inline] - fn unsigned_shl(self, n: u32) -> Self { - self << n - } - - #[inline] - fn unsigned_shr(self, n: u32) -> Self { - Self::from_bits(self.to_bits() >> n) - } - } - //} - - impl Roots for $BInt { - #[inline] - fn sqrt(&self) -> Self { - if self.is_negative() { - panic!(crate::errors::err_msg!("imaginary square root")) - } else { - Self::from_bits(self.bits.sqrt()) - } - } - - #[inline] - fn cbrt(&self) -> Self { - if self.is_negative() { - let out = Self::from_bits(self.unsigned_abs().cbrt()); - -out - } else { - Self::from_bits(self.bits.cbrt()) - } - } - - #[inline] - fn nth_root(&self, n: u32) -> Self { - if self.is_negative() { - if n == 0 { - panic!(crate::errors::err_msg!("attempt to calculate zeroth root")); - } - if n == 1 { - return *self; - } - if n.is_even() { - panic!("{} imaginary root degree of {}", errors::err_prefix!(), n) - } else { - let out = Self::from_bits(self.unsigned_abs().nth_root(n)); - out.wrapping_neg() - } - } else { - Self::from_bits(self.bits.nth_root(n)) - } - } - } - - //crate::nightly::impl_const! { - impl ToPrimitive for $BInt { - to_uint! { - to_u8 -> u8, - to_u16 -> u16, - to_u32 -> u32, - to_u64 -> u64, - to_u128 -> u128, - to_usize -> usize - } - - to_int! { - $Digit; - to_i8 -> i8, - to_i16 -> i16, - to_i32 -> i32, - to_i64 -> i64, - to_i128 -> i128, - to_isize -> isize - } - - #[inline] - fn to_f32(&self) -> Option { - Some(self.as_()) - } - - #[inline] - fn to_f64(&self) -> Option { - Some(self.as_()) - } - } - //} - - //crate::nightly::impl_const! { - impl Signed for $BInt { - #[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.signed_digit().is_negative() - } - } - //} - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::types::itest; - - crate::int::numtraits::tests!(itest); - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + crate::int::numtraits::impls!($BInt, $BUint, $BInt); + + impl FromPrimitive for $BInt { + from_uint!($Digit; u8, from_u8); + from_uint!($Digit; u16, from_u16); + from_uint!($Digit; u32, from_u32); + from_uint!($Digit; u64, from_u64); + from_uint!($Digit; u128, from_u128); + from_uint!($Digit; usize, from_usize); + from_int!($BUint, $Digit; i8, from_i8); + from_int!($BUint, $Digit; i16, from_i16); + from_int!($BUint, $Digit; i32, from_i32); + from_int!($BUint, $Digit; i64, from_i64); + from_int!($BUint, $Digit; i128, from_i128); + from_int!($BUint, $Digit; isize, from_isize); + + from_float!($BUint; from_f32, f32); + from_float!($BUint; from_f64, f64); + } + + //crate::nightly::impl_const! { + impl Integer for $BInt { + #[inline] + fn div_floor(&self, other: &Self) -> Self { + *self / *other + } + + #[inline] + fn mod_floor(&self, other: &Self) -> Self { + *self % *other + } + + #[inline] + fn gcd(&self, other: &Self) -> Self { + let gcd = self.unsigned_abs().gcd(&other.unsigned_abs()); + let out = Self::from_bits(gcd); + if out == Self::MIN { + panic!("{}", errors::err_msg!("gcd of is too large")); + } + out.abs() + } + + #[inline] + fn lcm(&self, other: &Self) -> Self { + self.div_floor(&self.gcd(other)) * *other + } + + #[inline] + fn divides(&self, other: &Self) -> bool { + self.is_multiple_of(other) + } + + #[inline] + fn is_multiple_of(&self, other: &Self) -> bool { + self.mod_floor(other).is_zero() + } + + #[inline] + fn is_even(&self) -> bool { + self.bits.is_even() + } + + #[inline] + fn is_odd(&self) -> bool { + self.bits.is_odd() + } + + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self) { + (self.div_floor(other), self.mod_floor(other)) + } + } + //} + + //crate::nightly::impl_const! { + impl PrimInt for $BInt { + crate::int::numtraits::prim_int_methods!(); + + #[inline] + fn signed_shl(self, n: u32) -> Self { + self << n + } + + #[inline] + fn signed_shr(self, n: u32) -> Self { + self >> n + } + + #[inline] + fn unsigned_shl(self, n: u32) -> Self { + self << n + } + + #[inline] + fn unsigned_shr(self, n: u32) -> Self { + Self::from_bits(self.to_bits() >> n) + } + } + //} + + impl Roots for $BInt { + #[inline] + fn sqrt(&self) -> Self { + if self.is_negative() { + panic!(crate::errors::err_msg!("imaginary square root")) + } else { + Self::from_bits(self.bits.sqrt()) + } + } + + #[inline] + fn cbrt(&self) -> Self { + if self.is_negative() { + let out = Self::from_bits(self.unsigned_abs().cbrt()); + -out + } else { + Self::from_bits(self.bits.cbrt()) + } + } + + #[inline] + fn nth_root(&self, n: u32) -> Self { + if self.is_negative() { + if n == 0 { + panic!(crate::errors::err_msg!("attempt to calculate zeroth root")); + } + if n == 1 { + return *self; + } + if n.is_even() { + panic!("{} imaginary root degree of {}", errors::err_prefix!(), n) + } else { + let out = Self::from_bits(self.unsigned_abs().nth_root(n)); + out.wrapping_neg() + } + } else { + Self::from_bits(self.bits.nth_root(n)) + } + } + } + + //crate::nightly::impl_const! { + impl ToPrimitive for $BInt { + to_uint! { + to_u8 -> u8, + to_u16 -> u16, + to_u32 -> u32, + to_u64 -> u64, + to_u128 -> u128, + to_usize -> usize + } + + to_int! { + $Digit; + to_i8 -> i8, + to_i16 -> i16, + to_i32 -> i32, + to_i64 -> i64, + to_i128 -> i128, + to_isize -> isize + } + + #[inline] + fn to_f32(&self) -> Option { + Some(self.as_()) + } + + #[inline] + fn to_f64(&self) -> Option { + Some(self.as_()) + } + } + //} + + //crate::nightly::impl_const! { + impl Signed for $BInt { + #[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.signed_digit().is_negative() + } + } + //} + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::types::itest; + + crate::int::numtraits::tests!(itest); + } + } + }; } crate::macro_impl!(numtraits); diff --git a/src/bint/ops.rs b/src/bint/ops.rs index 447f5d0..7121db0 100644 --- a/src/bint/ops.rs +++ b/src/bint/ops.rs @@ -5,112 +5,112 @@ use core::ops::{ }; macro_rules! ops { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - crate::nightly::impl_const! { - impl const Neg for $BInt { - type Output = Self; - - #[inline] - fn neg(self) -> Self { - Self::neg(self) - } - } - } - - crate::nightly::impl_const! { - impl const Neg for &$BInt { - type Output = $BInt; - - #[inline] - fn neg(self) -> $BInt { - $BInt::neg(*self) - } - } - } - - crate::nightly::impl_const! { - impl const BitAnd for $BInt { - type Output = Self; - - #[inline] - fn bitand(self, rhs: Self) -> Self { - Self::bitand(self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const BitOr for $BInt { - type Output = Self; - - #[inline] - fn bitor(self, rhs: Self) -> Self { - Self::bitor(self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const BitXor for $BInt { - type Output = Self; - - #[inline] - fn bitxor(self, rhs: Self) -> Self { - Self::bitxor(self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const Div for $BInt { - type Output = Self; - - #[inline] - fn div(self, rhs: Self) -> Self { - Self::div(self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const Not for $BInt { - type Output = Self; - - fn not(self) -> Self { - Self::not(self) - } - } - } - - crate::nightly::impl_const! { - impl const Rem for $BInt { - type Output = Self; - - #[inline] - fn rem(self, rhs: Self) -> Self { - Self::rem(self, rhs) - } - } - } - - crate::int::ops::impls!($BInt, $BUint, $BInt); - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use super::*; - use crate::test::{debug_skip, test_bignum, types::itest}; - use crate::test::types::big_types::$Digit::*; - - crate::int::ops::tests!(itest); - - test_bignum! { - function: ::neg(a: itest), - skip: debug_skip!(a == itest::MIN) - } - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + crate::nightly::impl_const! { + impl const Neg for $BInt { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + Self::neg(self) + } + } + } + + crate::nightly::impl_const! { + impl const Neg for &$BInt { + type Output = $BInt; + + #[inline] + fn neg(self) -> $BInt { + $BInt::neg(*self) + } + } + } + + crate::nightly::impl_const! { + impl const BitAnd for $BInt { + type Output = Self; + + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self::bitand(self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const BitOr for $BInt { + type Output = Self; + + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self::bitor(self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const BitXor for $BInt { + type Output = Self; + + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self::bitxor(self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const Div for $BInt { + type Output = Self; + + #[inline] + fn div(self, rhs: Self) -> Self { + Self::div(self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const Not for $BInt { + type Output = Self; + + fn not(self) -> Self { + Self::not(self) + } + } + } + + crate::nightly::impl_const! { + impl const Rem for $BInt { + type Output = Self; + + #[inline] + fn rem(self, rhs: Self) -> Self { + Self::rem(self, rhs) + } + } + } + + crate::int::ops::impls!($BInt, $BUint, $BInt); + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use super::*; + use crate::test::{debug_skip, test_bignum, types::itest}; + use crate::test::types::big_types::$Digit::*; + + crate::int::ops::tests!(itest); + + test_bignum! { + function: ::neg(a: itest), + skip: debug_skip!(a == itest::MIN) + } + } + } + }; } crate::macro_impl!(ops); diff --git a/src/bint/overflowing.rs b/src/bint/overflowing.rs index fa88b95..1130fb9 100644 --- a/src/bint/overflowing.rs +++ b/src/bint/overflowing.rs @@ -18,7 +18,8 @@ macro_rules! overflowing { let mut i = 0; while i < Self::N_MINUS_1 { - let (sum, c) = digit::$Digit::carrying_add(self_digits[i], rhs_digits[i], carry); + let (sum, c) = + digit::$Digit::carrying_add(self_digits[i], rhs_digits[i], carry); out.bits.digits[i] = sum; carry = c; i += 1; @@ -81,23 +82,23 @@ macro_rules! overflowing { const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType; - #[doc = doc::overflowing::overflowing_mul!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (uint, overflow) = self.unsigned_abs().overflowing_mul(rhs.unsigned_abs()); - let out = Self::from_bits(uint); - if self.is_negative() == rhs.is_negative() { - (out, overflow || out.is_negative()) - } else { - match out.checked_neg() { - Some(n) => (n, overflow || out.is_negative()), - None => (out, overflow), - } - } - } - - crate::nightly::const_fns! { + #[doc = doc::overflowing::overflowing_mul!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (uint, overflow) = self.unsigned_abs().overflowing_mul(rhs.unsigned_abs()); + let out = Self::from_bits(uint); + if self.is_negative() == rhs.is_negative() { + (out, overflow || out.is_negative()) + } else { + match out.checked_neg() { + Some(n) => (n, overflow || out.is_negative()), + None => (out, overflow), + } + } + } + + crate::nightly::const_fns! { #[inline] pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) { if self.eq(&Self::MIN) && rhs.is_one() { @@ -195,156 +196,155 @@ macro_rules! overflowing { (rem, false) } } - } + } - #[doc = doc::overflowing::overflowing_neg!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_neg(mut self) -> (Self, bool) { - let mut i = 0; - while i < N - 1 { - let (s, o) = (!self.bits.digits[i]).overflowing_add(1); // TODO: use overflowing add on signed integer digit instead - self.bits.digits[i] = s; - if !o { - i += 1; - while i < N { - self.bits.digits[i] = !self.bits.digits[i]; - i += 1; - } - return (self, false); - } - i += 1; - } - let (s, o) = (!self.bits.digits[i] as digit::$Digit::SignedDigit).overflowing_add(1); - self.bits.digits[i] = s as $Digit; - (self, o) - } + #[doc = doc::overflowing::overflowing_neg!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_neg(mut self) -> (Self, bool) { + let mut i = 0; + while i < N - 1 { + let (s, o) = (!self.bits.digits[i]).overflowing_add(1); // TODO: use overflowing add on signed integer digit instead + self.bits.digits[i] = s; + if !o { + i += 1; + while i < N { + self.bits.digits[i] = !self.bits.digits[i]; + i += 1; + } + return (self, false); + } + i += 1; + } + let (s, o) = + (!self.bits.digits[i] as digit::$Digit::SignedDigit).overflowing_add(1); + self.bits.digits[i] = s as $Digit; + (self, o) + } - crate::nightly::const_fns!{ - #[doc = doc::overflowing::overflowing_shl!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) { - let (uint, overflow) = self.bits.overflowing_shl(rhs); - (Self::from_bits(uint), overflow) - } + #[doc = doc::overflowing::overflowing_shl!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) { + let (uint, overflow) = self.bits.overflowing_shl(rhs); + (Self::from_bits(uint), overflow) + } - #[doc = doc::overflowing::overflowing_shr!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) { - let bits = self.to_bits(); - let (overflow, shift) = if rhs >= Self::BITS { - (true, rhs & Self::BITS_MINUS_1) - } else { - (false, rhs) - }; - let u = unsafe { - if self.is_negative() { - $BUint::unchecked_shr_pad_internal::<{$Digit::MAX}>(bits, shift) - } else { - $BUint::unchecked_shr_pad_internal::<{$Digit::MIN}>(bits, shift) - } - }; - (Self::from_bits(u), overflow) - } - } + #[doc = doc::overflowing::overflowing_shr!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) { + let bits = self.to_bits(); + let (overflow, shift) = if rhs >= Self::BITS { + (true, rhs & Self::BITS_MINUS_1) + } else { + (false, rhs) + }; + let u = unsafe { + if self.is_negative() { + $BUint::unchecked_shr_pad_internal::<{$Digit::MAX}>(bits, shift) + } else { + $BUint::unchecked_shr_pad_internal::<{$Digit::MIN}>(bits, shift) + } + }; + (Self::from_bits(u), overflow) + } - #[doc = doc::overflowing::overflowing_abs!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_abs(self) -> (Self, bool) { - if self.is_negative() { - self.overflowing_neg() - } else { - (self, false) - } - } + #[doc = doc::overflowing::overflowing_abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_abs(self) -> (Self, bool) { + if self.is_negative() { + self.overflowing_neg() + } else { + (self, false) + } + } - #[doc = doc::overflowing::overflowing_pow!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_pow(self, pow: ExpType) -> (Self, bool) { - let (u, mut overflow) = self.unsigned_abs().overflowing_pow(pow); - let out_neg = self.is_negative() && pow & 1 == 1; - let mut out = Self::from_bits(u); - if out_neg { - out = out.wrapping_neg(); - overflow = overflow || !out.is_negative(); - } else { - overflow = overflow || out.is_negative(); - } - (out, overflow) - } - } + #[doc = doc::overflowing::overflowing_pow!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_pow(self, pow: ExpType) -> (Self, bool) { + let (u, mut overflow) = self.unsigned_abs().overflowing_pow(pow); + let out_neg = self.is_negative() && pow & 1 == 1; + let mut out = Self::from_bits(u); + if out_neg { + out = out.wrapping_neg(); + overflow = overflow || !out.is_negative(); + } else { + overflow = overflow || out.is_negative(); + } + (out, overflow) + } + } #[cfg(test)] paste::paste! { mod [<$Digit _digit_tests>] { - use crate::test::{test_bignum, types::itest}; - use crate::test::types::big_types::$Digit::*; + use crate::test::{test_bignum, types::itest}; + use crate::test::types::big_types::$Digit::*; - test_bignum! { - function: ::overflowing_add(a: itest, b: itest) - } - test_bignum! { - function: ::overflowing_sub(a: itest, b: itest) - } - test_bignum! { - function: ::overflowing_mul(a: itest, b: itest) - } - test_bignum! { - function: ::overflowing_div(a: itest, b: itest), - skip: b == 0, - cases: [ - (itest::MIN, -1i8) - ] - } - test_bignum! { - function: ::overflowing_div_euclid(a: itest, b: itest), - skip: b == 0, - cases: [ - (itest::MIN, -1i8) - ] - } - test_bignum! { - function: ::overflowing_rem(a: itest, b: itest), - skip: b == 0, - cases: [ - (itest::MIN, -1i8) - ] - } - test_bignum! { - function: ::overflowing_rem_euclid(a: itest, b: itest), - skip: b == 0, - cases: [ - (itest::MIN, -1i8) - ] - } - test_bignum! { - function: ::overflowing_neg(a: itest), - cases: [ - (0i8), - (itest::MIN) - ] - } - test_bignum! { - function: ::overflowing_shl(a: itest, b: u16) - } - test_bignum! { - function: ::overflowing_shr(a: itest, b: u16) - } - test_bignum! { - function: ::overflowing_abs(a: itest), - cases: [ - (0i8), - (itest::MIN) - ] - } - test_bignum! { - function: ::overflowing_pow(a: itest, b: u16) - } - } + test_bignum! { + function: ::overflowing_add(a: itest, b: itest) + } + test_bignum! { + function: ::overflowing_sub(a: itest, b: itest) + } + test_bignum! { + function: ::overflowing_mul(a: itest, b: itest) + } + test_bignum! { + function: ::overflowing_div(a: itest, b: itest), + skip: b == 0, + cases: [ + (itest::MIN, -1i8) + ] + } + test_bignum! { + function: ::overflowing_div_euclid(a: itest, b: itest), + skip: b == 0, + cases: [ + (itest::MIN, -1i8) + ] + } + test_bignum! { + function: ::overflowing_rem(a: itest, b: itest), + skip: b == 0, + cases: [ + (itest::MIN, -1i8) + ] + } + test_bignum! { + function: ::overflowing_rem_euclid(a: itest, b: itest), + skip: b == 0, + cases: [ + (itest::MIN, -1i8) + ] + } + test_bignum! { + function: ::overflowing_neg(a: itest), + cases: [ + (0i8), + (itest::MIN) + ] + } + test_bignum! { + function: ::overflowing_shl(a: itest, b: u16) + } + test_bignum! { + function: ::overflowing_shr(a: itest, b: u16) + } + test_bignum! { + function: ::overflowing_abs(a: itest), + cases: [ + (0i8), + (itest::MIN) + ] + } + test_bignum! { + function: ::overflowing_pow(a: itest, b: u16) + } + } } }; } diff --git a/src/bint/radix.rs b/src/bint/radix.rs index 19d8fd7..a3da1d6 100644 --- a/src/bint/radix.rs +++ b/src/bint/radix.rs @@ -20,31 +20,31 @@ macro_rules! radix { crate::nightly::ok!(Self::from_str_radix(s, radix)) } - crate::nightly::const_fns! { - /// Converts a slice of big-endian digits in the given radix to an integer. The digits are first converted to an unsigned integer, then this is transmuted to a signed integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. - /// - /// For examples, see the - #[doc = concat!("[`from_radix_be`](crate::", stringify!($BUint), "::from_radix_be) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] - #[inline] - pub const fn from_radix_be(buf: &[u8], radix: u32) -> Option { - match $BUint::from_radix_be(buf, radix) { // TODO: use Option::map when stable - Some(uint) => Some(Self::from_bits(uint)), - None => None, - } - } + crate::nightly::const_fns! { + /// Converts a slice of big-endian digits in the given radix to an integer. The digits are first converted to an unsigned integer, then this is transmuted to a signed integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. + /// + /// For examples, see the + #[doc = concat!("[`from_radix_be`](crate::", stringify!($BUint), "::from_radix_be) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] + #[inline] + pub const fn from_radix_be(buf: &[u8], radix: u32) -> Option { + match $BUint::from_radix_be(buf, radix) { // TODO: use Option::map when stable + Some(uint) => Some(Self::from_bits(uint)), + None => None, + } + } - /// Converts a slice of big-endian digits in the given radix to an integer. The digits are first converted to an unsigned integer, then this is transmuted to a signed integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. - /// - /// For examples, see the - #[doc = concat!("[`from_radix_le`](crate::", stringify!($BUint), "::from_radix_le) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] - #[inline] - pub const fn from_radix_le(buf: &[u8], radix: u32) -> Option { - match $BUint::from_radix_le(buf, radix) { // TODO: use Option::map when stable - Some(uint) => Some(Self::from_bits(uint)), - None => None, - } - } - } + /// Converts a slice of big-endian digits in the given radix to an integer. The digits are first converted to an unsigned integer, then this is transmuted to a signed integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. + /// + /// For examples, see the + #[doc = concat!("[`from_radix_le`](crate::", stringify!($BUint), "::from_radix_le) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] + #[inline] + pub const fn from_radix_le(buf: &[u8], radix: u32) -> Option { + match $BUint::from_radix_le(buf, radix) { // TODO: use Option::map when stable + Some(uint) => Some(Self::from_bits(uint)), + None => None, + } + } + } /// Converts a string slice in a given base to an integer. /// @@ -59,29 +59,29 @@ macro_rules! radix { /// This function panics if `radix` is not in the range from 2 to 36 inclusive. /// /// For examples, see the - #[doc = concat!("[`from_str_radix`](crate::", stringify!($BUint), "::from_str_radix) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] + #[doc = concat!("[`from_str_radix`](crate::", stringify!($BUint), "::from_str_radix) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] #[inline] pub const fn from_str_radix(src: &str, radix: u32) -> Result { - assert_range!(radix, 36); - if src.is_empty() { - return Err(ParseIntError { - kind: IntErrorKind::Empty, - }); - } - let mut negative = false; - let mut leading_sign = false; - let buf = src.as_bytes(); - if buf[0] == b'-' { - negative = true; - leading_sign = true; - } else if buf[0] == b'+' { - leading_sign = true; - } - + assert_range!(radix, 36); + if src.is_empty() { + return Err(ParseIntError { + kind: IntErrorKind::Empty, + }); + } + let mut negative = false; + let mut leading_sign = false; + let buf = src.as_bytes(); + if buf[0] == b'-' { + negative = true; + leading_sign = true; + } else if buf[0] == b'+' { + leading_sign = true; + } + match $BUint::from_buf_radix_internal::(buf, radix, leading_sign) { Ok(uint) => { if negative { - if uint.bit(Self::BITS - 1) && uint.trailing_zeros() != Self::BITS - 1 { + if uint.bit(Self::BITS - 1) && uint.trailing_zeros() != Self::BITS - 1 { Err(ParseIntError { kind: IntErrorKind::NegOverflow, }) @@ -102,24 +102,24 @@ macro_rules! radix { Err(err) => { if let IntErrorKind::PosOverflow = err.kind() { if negative { - return Err(ParseIntError { - kind: IntErrorKind::NegOverflow, - }); - } + return Err(ParseIntError { + kind: IntErrorKind::NegOverflow, + }); + } } - return Err(err) + return Err(err) } } } - #[doc = doc::radix::parse_str_radix!($BUint)] - #[inline] - pub const fn parse_str_radix(src: &str, radix: u32) -> Self { - match Self::from_str_radix(src, radix) { - Ok(n) => n, - Err(e) => panic!("{}", e.description()), - } - } + #[doc = doc::radix::parse_str_radix!($BUint)] + #[inline] + pub const fn parse_str_radix(src: &str, radix: u32) -> Self { + match Self::from_str_radix(src, radix) { + Ok(n) => n, + Err(e) => panic!("{}", e.description()), + } + } /// Returns the integer as a string in the given radix. /// @@ -128,7 +128,7 @@ macro_rules! radix { /// This function panics if `radix` is not in the range from 2 to 36 inclusive. /// /// For examples, see the - #[doc = concat!("[`to_str_radix`](crate::", stringify!($BUint), "::to_str_radix) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] + #[doc = concat!("[`to_str_radix`](crate::", stringify!($BUint), "::to_str_radix) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] #[inline] pub fn to_str_radix(&self, radix: u32) -> String { if self.is_negative() { @@ -145,7 +145,7 @@ macro_rules! radix { /// This function panics if `radix` is not in the range from 2 to 256 inclusive. /// /// For examples, see the - #[doc = concat!("[`to_radix_be`](crate::", stringify!($BUint), "::to_radix_be) method documentation for [`", stringify!($BUint), "`]")] + #[doc = concat!("[`to_radix_be`](crate::", stringify!($BUint), "::to_radix_be) method documentation for [`", stringify!($BUint), "`]")] #[inline] pub fn to_radix_be(&self, radix: u32) -> Vec { self.bits.to_radix_be(radix) @@ -158,7 +158,7 @@ macro_rules! radix { /// This function panics if `radix` is not in the range from 2 to 256 inclusive. /// /// For examples, see the - #[doc = concat!("[`to_radix_le`](crate::", stringify!($BUint), "::to_radix_le) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] + #[doc = concat!("[`to_radix_le`](crate::", stringify!($BUint), "::to_radix_le) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")] #[inline] pub fn to_radix_le(&self, radix: u32) -> Vec { self.bits.to_radix_le(radix) @@ -166,134 +166,134 @@ macro_rules! radix { } #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::{quickcheck_from_to_radix, test_bignum, self}; - use crate::$BInt; - use crate::test::types::itest; + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::{quickcheck_from_to_radix, test_bignum, self}; + use crate::$BInt; + use crate::test::types::itest; - test_bignum! { - function: ::from_str_radix, - cases: [ - ("-14359abcasdhfkdgdfgsde", 34u32), - ("+23797984569ahgkhhjdskjdfiu", 32u32), - ("-253613132341435345", 7u32), - ("+23467abcad47790809ef37", 16u32), - ("-712930769245766867875986646", 10u32), - ("-😱234292", 36u32), - ("-+345934758", 13u32), - ("12💯12", 15u32), - ("gap gap", 36u32), - ("-9223372036854775809", 10u32), - ("-1000000000000000000001", 8u32), - ("+1000000000000000000001", 8u32), - ("-8000000000000001", 16u32), - ("+-23459374", 15u32), - ("8000000000000000", 16u32) - ] - } + test_bignum! { + function: ::from_str_radix, + cases: [ + ("-14359abcasdhfkdgdfgsde", 34u32), + ("+23797984569ahgkhhjdskjdfiu", 32u32), + ("-253613132341435345", 7u32), + ("+23467abcad47790809ef37", 16u32), + ("-712930769245766867875986646", 10u32), + ("-😱234292", 36u32), + ("-+345934758", 13u32), + ("12💯12", 15u32), + ("gap gap", 36u32), + ("-9223372036854775809", 10u32), + ("-1000000000000000000001", 8u32), + ("+1000000000000000000001", 8u32), + ("-8000000000000001", 16u32), + ("+-23459374", 15u32), + ("8000000000000000", 16u32) + ] + } - quickcheck_from_to_radix!(itest, radix_be, 256); - quickcheck_from_to_radix!(itest, radix_le, 256); - quickcheck_from_to_radix!(itest, str_radix, 36); + quickcheck_from_to_radix!(itest, radix_be, 256); + quickcheck_from_to_radix!(itest, radix_le, 256); + quickcheck_from_to_radix!(itest, str_radix, 36); - test::quickcheck_from_str_radix!(itest, "+" | "-"); - test::quickcheck_from_str!(itest); + test::quickcheck_from_str_radix!(itest, "+" | "-"); + test::quickcheck_from_str!(itest); - #[test] - fn from_to_radix_le() { - let buf = &[ - 61, 45, 48, 20, 37, 59, 53, 28, 28, 52, 54, 13, 44, 3, 46, 42, 20, 46, 37, 32, - 13, 27, 47, 30, 33, 25, 3, 32, 4, 54, 53, 6, 44, 25, 10, 22, 33, 48, 7, 17, - ]; - let u = $BInt::<100>::from_radix_le(buf, 64).unwrap(); - let v = u.to_radix_le(64); - assert_eq!(v, buf); + #[test] + fn from_to_radix_le() { + let buf = &[ + 61, 45, 48, 20, 37, 59, 53, 28, 28, 52, 54, 13, 44, 3, 46, 42, 20, 46, 37, 32, + 13, 27, 47, 30, 33, 25, 3, 32, 4, 54, 53, 6, 44, 25, 10, 22, 33, 48, 7, 17, + ]; + let u = $BInt::<100>::from_radix_le(buf, 64).unwrap(); + let v = u.to_radix_le(64); + assert_eq!(v, buf); - let buf = &[ - 33, 34, 61, 53, 74, 67, 54, 62, 22, 29, 4, 2, 43, 73, 74, 24, 8, 74, 65, 3, 78, - ]; - let option = $BInt::<100>::from_radix_le(buf, 78); - assert!(option.is_none()); + let buf = &[ + 33, 34, 61, 53, 74, 67, 54, 62, 22, 29, 4, 2, 43, 73, 74, 24, 8, 74, 65, 3, 78, + ]; + let option = $BInt::<100>::from_radix_le(buf, 78); + assert!(option.is_none()); - let buf = &[ - 1, 3, 3, 0, 2, 1, 2, 3, 0, 4, 1, 2, 0, 0, 0, 0, 3, 2, 0, 1, 0, 4, 1, 3, 1, 4, - 3, 3, 3, 4, 1, 2, 2, 1, 3, 0, 2, 1, 2, 3, 1, 1, 0, 2, 2, 1, 1, 2, 1, 0, 0, 0, - 3, 3, 3, 0, 0, 4, 4, 2, - ]; - let u = $BInt::<100>::from_radix_le(buf, 5).unwrap(); - let v = u.to_radix_le(5); - assert_eq!(v, buf); - } - #[test] - fn from_to_radix_be() { - let buf = &[ - 29, 89, 92, 118, 69, 140, 141, 70, 71, 76, 66, 13, 30, 28, 38, 145, 40, 7, 57, - 18, 25, 65, 150, 119, 155, 18, 64, 76, 106, 87, - ]; - let u = $BInt::<100>::from_radix_be(buf, 157).unwrap(); - let v = u.to_radix_be(157); - assert_eq!(v, buf); + let buf = &[ + 1, 3, 3, 0, 2, 1, 2, 3, 0, 4, 1, 2, 0, 0, 0, 0, 3, 2, 0, 1, 0, 4, 1, 3, 1, 4, + 3, 3, 3, 4, 1, 2, 2, 1, 3, 0, 2, 1, 2, 3, 1, 1, 0, 2, 2, 1, 1, 2, 1, 0, 0, 0, + 3, 3, 3, 0, 0, 4, 4, 2, + ]; + let u = $BInt::<100>::from_radix_le(buf, 5).unwrap(); + let v = u.to_radix_le(5); + assert_eq!(v, buf); + } + #[test] + fn from_to_radix_be() { + let buf = &[ + 29, 89, 92, 118, 69, 140, 141, 70, 71, 76, 66, 13, 30, 28, 38, 145, 40, 7, 57, + 18, 25, 65, 150, 119, 155, 18, 64, 76, 106, 87, + ]; + let u = $BInt::<100>::from_radix_be(buf, 157).unwrap(); + let v = u.to_radix_be(157); + assert_eq!(v, buf); - let buf = &[ - 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, - 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, - 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, - 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, - ]; - let u = $BInt::<100>::from_radix_be(buf, 2).unwrap(); - let v = u.to_radix_be(2); - assert_eq!(v, buf); + let buf = &[ + 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, + ]; + let u = $BInt::<100>::from_radix_be(buf, 2).unwrap(); + let v = u.to_radix_be(2); + assert_eq!(v, buf); - let buf = &[ - 91, 167, 5, 99, 61, 38, 158, 149, 115, 79, 13, 118, 53, 16, 144, 123, 70, 81, - 78, 61, 39, 6, 34, 95, 98, 23, 175, 182, - ]; - let option = $BInt::<100>::from_radix_le(buf, 180); - assert!(option.is_none()); + let buf = &[ + 91, 167, 5, 99, 61, 38, 158, 149, 115, 79, 13, 118, 53, 16, 144, 123, 70, 81, + 78, 61, 39, 6, 34, 95, 98, 23, 175, 182, + ]; + let option = $BInt::<100>::from_radix_le(buf, 180); + assert!(option.is_none()); - let buf = &[ - 39, 90, 119, 93, 95, 7, 70, 81, 3, 100, 39, 107, 98, 31, 61, 5, 36, 19, 18, - 124, 4, 77, 119, 17, 121, 116, 24, 35, - ]; - let u = $BInt::<100>::from_radix_be(buf, 128).unwrap(); - let v = u.to_radix_be(128); - assert_eq!(v, buf); - } - #[test] - fn from_to_str_radix() { - let src = "-293487598aashkhkhakb8345cbvjkus"; - let u = $BInt::<100>::from_str_radix(src, 35).unwrap(); - let v = u.to_str_radix(35); - assert_eq!(v, src); + let buf = &[ + 39, 90, 119, 93, 95, 7, 70, 81, 3, 100, 39, 107, 98, 31, 61, 5, 36, 19, 18, + 124, 4, 77, 119, 17, 121, 116, 24, 35, + ]; + let u = $BInt::<100>::from_radix_be(buf, 128).unwrap(); + let v = u.to_radix_be(128); + assert_eq!(v, buf); + } + #[test] + fn from_to_str_radix() { + let src = "-293487598aashkhkhakb8345cbvjkus"; + let u = $BInt::<100>::from_str_radix(src, 35).unwrap(); + let v = u.to_str_radix(35); + assert_eq!(v, src); - let src = "zzzzzzzzzzzzzzzzzzzzzzzzz"; - let result = $BInt::<1>::from_str_radix(src, 36); - assert!(result.is_err()); + let src = "zzzzzzzzzzzzzzzzzzzzzzzzz"; + let result = $BInt::<1>::from_str_radix(src, 36); + assert!(result.is_err()); - let invalid = "inval_id string"; - let result = $BInt::<1>::from_str_radix(invalid, 36); - assert!(result.is_err()); + let invalid = "inval_id string"; + let result = $BInt::<1>::from_str_radix(invalid, 36); + assert!(result.is_err()); - let src = "72954hslfhbui79845y6audfgiu984h5ihhhdfg"; - let u = $BInt::<100>::from_str_radix(src, 36).unwrap(); - assert_eq!(u.to_str_radix(36), src); - } - #[test] - fn parse_bytes() { - let src = "1797972456987acbdead7889"; - let u = $BInt::<100>::parse_bytes(src.as_bytes(), 16).unwrap(); - let v = $BInt::<100>::from_str_radix(src, 16).unwrap(); - assert_eq!(u, v); - assert_eq!(v.to_str_radix(16), src); + let src = "72954hslfhbui79845y6audfgiu984h5ihhhdfg"; + let u = $BInt::<100>::from_str_radix(src, 36).unwrap(); + assert_eq!(u.to_str_radix(36), src); + } + #[test] + fn parse_bytes() { + let src = "1797972456987acbdead7889"; + let u = $BInt::<100>::parse_bytes(src.as_bytes(), 16).unwrap(); + let v = $BInt::<100>::from_str_radix(src, 16).unwrap(); + assert_eq!(u, v); + assert_eq!(v.to_str_radix(16), src); - let bytes = b"279874657dgfhjh"; - let option = $BInt::<100>::parse_bytes(bytes, 11); - assert!(option.is_none()); - } - } - } + let bytes = b"279874657dgfhjh"; + let option = $BInt::<100>::parse_bytes(bytes, 11); + assert!(option.is_none()); + } + } + } }; } diff --git a/src/bint/saturating.rs b/src/bint/saturating.rs index 7d41ab0..6807b90 100644 --- a/src/bint/saturating.rs +++ b/src/bint/saturating.rs @@ -56,23 +56,23 @@ macro_rules! saturating { } } - #[doc = doc::saturating::saturating_mul!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_mul(self, rhs: Self) -> Self { - match self.checked_mul(rhs) { - Some(mul) => mul, - None => { - if self.is_negative() == rhs.is_negative() { - Self::MAX - } else { - Self::MIN - } - } - } - } - - crate::nightly::const_fns! { + #[doc = doc::saturating::saturating_mul!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(mul) => mul, + None => { + if self.is_negative() == rhs.is_negative() { + Self::MAX + } else { + Self::MIN + } + } + } + } + + crate::nightly::const_fns! { #[doc = doc::saturating::saturating_div!(I)] #[must_use = doc::must_use_op!()] #[inline] @@ -84,49 +84,49 @@ macro_rules! saturating { div } } - } + } - #[doc = doc::saturating::saturating_neg!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_neg(self) -> Self { - match self.checked_neg() { - Some(abs) => abs, - None => Self::MAX, - } - } + #[doc = doc::saturating::saturating_neg!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_neg(self) -> Self { + match self.checked_neg() { + Some(abs) => abs, + None => Self::MAX, + } + } - #[doc = doc::saturating::saturating_abs!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_abs(self) -> Self { - match self.checked_abs() { - Some(abs) => abs, - None => Self::MAX, - } - } + #[doc = doc::saturating::saturating_abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_abs(self) -> Self { + match self.checked_abs() { + Some(abs) => abs, + None => Self::MAX, + } + } - #[doc = doc::saturating::saturating_pow!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_pow(self, exp: ExpType) -> Self { - match self.checked_pow(exp) { - Some(pow) => pow, - None => { - if self.is_negative() && exp & 1 != 0 { - Self::MIN - } else { - Self::MAX - } - }, - } - } + #[doc = doc::saturating::saturating_pow!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_pow(self, exp: ExpType) -> Self { + match self.checked_pow(exp) { + Some(pow) => pow, + None => { + if self.is_negative() && exp & 1 != 0 { + Self::MIN + } else { + Self::MAX + } + } + } + } } #[cfg(test)] paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; use crate::test::{test_bignum, types::*}; test_bignum! { diff --git a/src/bint/wrapping.rs b/src/bint/wrapping.rs index dfeda22..982d199 100644 --- a/src/bint/wrapping.rs +++ b/src/bint/wrapping.rs @@ -48,7 +48,7 @@ macro_rules! wrapping { } #[doc = doc::wrapping::wrapping_div_euclid!(I)] - #[must_use = doc::must_use_op!()] + #[must_use = doc::must_use_op!()] #[inline] pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { self.overflowing_div_euclid(rhs).0 @@ -67,37 +67,35 @@ macro_rules! wrapping { pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { self.overflowing_rem_euclid(rhs).0 } - } + } - #[doc = doc::wrapping::wrapping_neg!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } + #[doc = doc::wrapping::wrapping_neg!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } - crate::nightly::const_fns! { - #[doc = doc::wrapping::wrapping_shl!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_shl(self, rhs: ExpType) -> Self { - self.overflowing_shl(rhs).0 - } + #[doc = doc::wrapping::wrapping_shl!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_shl(self, rhs: ExpType) -> Self { + self.overflowing_shl(rhs).0 + } - #[doc = doc::wrapping::wrapping_shr!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_shr(self, rhs: ExpType) -> Self { - self.overflowing_shr(rhs).0 - } - } + #[doc = doc::wrapping::wrapping_shr!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_shr(self, rhs: ExpType) -> Self { + self.overflowing_shr(rhs).0 + } - #[doc = doc::wrapping::wrapping_abs!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_abs(self) -> Self { - self.overflowing_abs().0 - } + #[doc = doc::wrapping::wrapping_abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_abs(self) -> Self { + self.overflowing_abs().0 + } #[doc = doc::wrapping::wrapping_pow!(I)] #[must_use = doc::must_use_op!()] @@ -110,8 +108,8 @@ macro_rules! wrapping { #[cfg(test)] paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; use crate::test::{test_bignum, types::itest}; test_bignum! { diff --git a/src/buint/bigint_helpers.rs b/src/buint/bigint_helpers.rs index 283e4ae..14fc9b8 100644 --- a/src/buint/bigint_helpers.rs +++ b/src/buint/bigint_helpers.rs @@ -83,11 +83,11 @@ macro_rules! bigint_helpers { #[cfg(test)] paste::paste! { - mod [<$Digit _digit_tests>] { + mod [<$Digit _digit_tests>] { use crate::test::{test_bignum, types::*}; use crate::test::types::big_types::$Digit::*; - type U64 = crate::$BUint::<{64 / $Digit::BITS as usize}>; + type U64 = crate::$BUint::<{64 / $Digit::BITS as usize}>; test_bignum! { function: ::carrying_add(a: utest, rhs: utest, carry: bool), diff --git a/src/buint/cast.rs b/src/buint/cast.rs index e9f0168..6b7f144 100644 --- a/src/buint/cast.rs +++ b/src/buint/cast.rs @@ -29,23 +29,23 @@ decode_float!(decode_f32, f32, u32); decode_float!(decode_f64, f64, u64); macro_rules! buint_as_int { - ($BUint: ident, $Digit: ident; $($int: ty), *) => { - $(impl_const! { - impl const CastFrom<$BUint> for $int { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $BUint) -> Self { - let mut out = 0; - let mut i = 0; - while i << crate::digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N { - out |= from.digits[i] as $int << (i << crate::digit::$Digit::BIT_SHIFT); - i += 1; - } - out - } - } - })* - }; + ($BUint: ident, $Digit: ident; $($int: ty), *) => { + $(impl_const! { + impl const CastFrom<$BUint> for $int { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $BUint) -> Self { + let mut out = 0; + let mut i = 0; + while i << crate::digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N { + out |= from.digits[i] as $int << (i << crate::digit::$Digit::BIT_SHIFT); + i += 1; + } + out + } + } + })* + }; } macro_rules! buint_as_float { @@ -98,34 +98,34 @@ macro_rules! buint_as_float { } macro_rules! as_buint { - ($BUint: ident, $Digit: ident; $($ty: ty), *) => { - $(impl_const! { - impl const CastFrom<$ty> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(mut from: $ty) -> Self { - #[allow(unused_comparisons)] - let mut out = if from < 0 { - Self::MAX - } else { - Self::MIN - }; - let mut i = 0; - while from != 0 && i < N { - let masked = from as $Digit & $Digit::MAX; - out.digits[i] = masked; - if <$ty>::BITS <= $Digit::BITS { - from = 0; - } else { - from = from.wrapping_shr($Digit::BITS); - } - i += 1; - } - out - } - } - })* - }; + ($BUint: ident, $Digit: ident; $($ty: ty), *) => { + $(impl_const! { + impl const CastFrom<$ty> for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(mut from: $ty) -> Self { + #[allow(unused_comparisons)] + let mut out = if from < 0 { + Self::MAX + } else { + Self::MIN + }; + let mut i = 0; + while from != 0 && i < N { + let masked = from as $Digit & $Digit::MAX; + out.digits[i] = masked; + if <$ty>::BITS <= $Digit::BITS { + from = 0; + } else { + from = from.wrapping_shr($Digit::BITS); + } + i += 1; + } + out + } + } + })* + }; } use crate::cast::CastFrom; @@ -135,146 +135,146 @@ use crate::ExpType; use core::mem::MaybeUninit; macro_rules! cast { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl $BUint { - crate::nightly::const_fn! { - #[inline] - const fn cast_up(self, digit: $Digit) -> $BUint { - let mut digits = [digit; M]; - let digits_ptr = digits.as_mut_ptr() as *mut $Digit; - let self_ptr = self.digits.as_ptr(); - unsafe { - self_ptr.copy_to_nonoverlapping(digits_ptr, N); - $BUint::from_digits(digits) - } - } - } - crate::nightly::const_fn! { - #[inline] - const fn cast_down(self) -> $BUint { - let mut digits = MaybeUninit::<[$Digit; M]>::uninit(); - let digits_ptr = digits.as_mut_ptr() as *mut $Digit; - let self_ptr = self.digits.as_ptr(); + ($BUint: ident, $BInt: ident, $Digit: ident) => { + impl $BUint { + crate::nightly::const_fn! { + #[inline] + const fn cast_up(self, digit: $Digit) -> $BUint { + let mut digits = [digit; M]; + let digits_ptr = digits.as_mut_ptr() as *mut $Digit; + let self_ptr = self.digits.as_ptr(); + unsafe { + self_ptr.copy_to_nonoverlapping(digits_ptr, N); + $BUint::from_digits(digits) + } + } + } + crate::nightly::const_fn! { + #[inline] + const fn cast_down(self) -> $BUint { + let mut digits = MaybeUninit::<[$Digit; M]>::uninit(); + let digits_ptr = digits.as_mut_ptr() as *mut $Digit; + let self_ptr = self.digits.as_ptr(); - unsafe { - self_ptr.copy_to_nonoverlapping(digits_ptr, M); - $BUint::from_digits(digits.assume_init()) - } - } - } - } + unsafe { + self_ptr.copy_to_nonoverlapping(digits_ptr, M); + $BUint::from_digits(digits.assume_init()) + } + } + } + } - buint_as_int!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + buint_as_int!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - buint_as_float!($BUint, $Digit; f32, u32); - buint_as_float!($BUint, $Digit; f64, u64); + buint_as_float!($BUint, $Digit; f32, u32); + buint_as_float!($BUint, $Digit; f64, u64); - as_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + as_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - impl_const! { - impl const CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: bool) -> Self { - if from { - Self::ONE - } else { - Self::ZERO - } - } - } - } + impl_const! { + impl const CastFrom for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: bool) -> Self { + if from { + Self::ONE + } else { + Self::ZERO + } + } + } + } - impl_const! { - impl const CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: char) -> Self { - Self::cast_from(from as u32) - } - } - } + impl_const! { + impl const CastFrom for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: char) -> Self { + Self::cast_from(from as u32) + } + } + } - impl_const! { - impl const CastFrom<$BUint> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $BUint) -> Self { - if M < N { - from.cast_up(0) - } else { - from.cast_down() - } - } - } - } + impl_const! { + impl const CastFrom<$BUint> for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $BUint) -> Self { + if M < N { + from.cast_up(0) + } else { + from.cast_down() + } + } + } + } - impl_const! { - impl const CastFrom<$BInt> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $BInt) -> Self { - if M < N { - let padding_digit = if from.is_negative() { - $Digit::MAX - } else { - 0 - }; - from.to_bits().cast_up(padding_digit) - } else { - from.to_bits().cast_down() - } - } - } - } + impl_const! { + impl const CastFrom<$BInt> for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $BInt) -> Self { + if M < N { + let padding_digit = if from.is_negative() { + $Digit::MAX + } else { + 0 + }; + from.to_bits().cast_up(padding_digit) + } else { + from.to_bits().cast_down() + } + } + } + } - macro_rules! cast_from_float { - ($f: ty, $exp_type: ty, $decoder: expr, $mant_bits: expr) => { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $f) -> Self { - if from.is_nan() { - return Self::ZERO; - } - if from.is_sign_negative() { - return Self::MIN; - } - if from.is_infinite() { - return Self::MAX; - } - let (mut mant, exp) = $decoder(from); - if exp.is_negative() { - mant = mant.checked_shr((-exp) as $exp_type).unwrap_or(0); - if $mant_bits(mant) > Self::BITS { - return Self::MAX; - } - Self::cast_from(mant) - } else { - if $mant_bits(mant) + exp as ExpType > Self::BITS { - return Self::MAX; - } - Self::cast_from(mant) << exp - } - } - }; - } + macro_rules! cast_from_float { + ($f: ty, $exp_type: ty, $decoder: expr, $mant_bits: expr) => { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $f) -> Self { + if from.is_nan() { + return Self::ZERO; + } + if from.is_sign_negative() { + return Self::MIN; + } + if from.is_infinite() { + return Self::MAX; + } + let (mut mant, exp) = $decoder(from); + if exp.is_negative() { + mant = mant.checked_shr((-exp) as $exp_type).unwrap_or(0); + if $mant_bits(mant) > Self::BITS { + return Self::MAX; + } + Self::cast_from(mant) + } else { + if $mant_bits(mant) + exp as ExpType > Self::BITS { + return Self::MAX; + } + Self::cast_from(mant) << exp + } + } + }; + } - impl CastFrom for $BUint { - cast_from_float!(f32, u32, decode_f32, u32_bits); - } + impl CastFrom for $BUint { + cast_from_float!(f32, u32, decode_f32, u32_bits); + } - impl CastFrom for $BUint { - cast_from_float!(f64, u32, decode_f64, u64_bits); - } + impl CastFrom for $BUint { + cast_from_float!(f64, u32, decode_f64, u64_bits); + } - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - crate::int::cast::tests!(utest); - } - } - }; + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + crate::int::cast::tests!(utest); + } + } + }; } crate::macro_impl!(cast); diff --git a/src/buint/checked.rs b/src/buint/checked.rs index 2666e7d..969812c 100644 --- a/src/buint/checked.rs +++ b/src/buint/checked.rs @@ -2,504 +2,501 @@ use crate::digit; use crate::doc; use crate::errors::div_zero; use crate::int::checked::tuple_to_option; -use crate::nightly::const_fns; use crate::ExpType; macro_rules! checked { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::checked::impl_desc!()] - impl $BUint { - #[doc = doc::checked::checked_add!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_add(self, rhs: Self) -> Option { - tuple_to_option(self.overflowing_add(rhs)) - } - - #[doc = doc::checked::checked_add_signed!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_add_signed(self, rhs: $BInt) -> Option { - tuple_to_option(self.overflowing_add_signed(rhs)) - } - - #[doc = doc::checked::checked_sub!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_sub(self, rhs: Self) -> Option { - tuple_to_option(self.overflowing_sub(rhs)) - } - - #[doc = doc::checked::checked_mul!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_mul(self, rhs: Self) -> Option { - tuple_to_option(self.overflowing_mul(rhs)) - } - - const_fns! { - pub(crate) const fn div_rem_digit(self, rhs: $Digit) -> (Self, $Digit) { - let mut out = Self::ZERO; - let mut rem: $Digit = 0; - let mut i = N; - while i > 0 { - i -= 1; - let (q, r) = digit::$Digit::div_rem_wide(self.digits[i], rem, rhs); - rem = r; - out.digits[i] = q; - } - (out, rem) - } - const fn basecase_div_rem(self, mut v: Self, n: usize) -> (Self, Self) { - // The Art of Computer Programming Volume 2 by Donald Knuth, Section 4.3.1, Algorithm D - - let mut q = Self::ZERO; - let m = self.last_digit_index() + 1 - n; - let shift = v.digits[n - 1].leading_zeros() as ExpType; - - v = unsafe { - Self::unchecked_shl_internal(v, shift) - }; // D1 - - struct Remainder { - first: $Digit, - rest: [$Digit; M], - } - impl Remainder { - const fn digit(&self, index: usize) -> $Digit { - if index == 0 { - self.first - } else { - self.rest[index - 1] - } - } - const fn shr(self, shift: ExpType) -> $BUint { - let mut out = $BUint::ZERO; - let mut i = 0; - while i < M { - out.digits[i] = self.digit(i) >> shift; - i += 1; - } - if shift > 0 { - i = 0; - while i < M { - out.digits[i] |= self.rest[i] << (digit::$Digit::BITS as ExpType - shift); - i += 1; - } - } - out - } - crate::nightly::const_fns! { - const fn new(uint: $BUint, shift: ExpType) -> Self { - let first = uint.digits[0] << shift; - let rest = uint.wrapping_shr(digit::$Digit::BITS - shift); - Self { - first, - rest: rest.digits, - } - } - const fn set_digit(&mut self, index: usize, digit: $Digit) -> () { - if index == 0 { - self.first = digit; - } else { - self.rest[index - 1] = digit; - } - } - const fn sub(&mut self, rhs: Mul, start: usize, range: usize) -> bool { - let mut borrow = false; - let mut i = 0; - while i <= range { - let (sub, overflow) = digit::$Digit::borrowing_sub(self.digit(i + start), rhs.digit(i), borrow); - self.set_digit(i + start, sub); - borrow = overflow; - i += 1; - } - borrow - } - const fn add(&mut self, rhs: $BUint, start: usize, range: usize) -> () { - let mut carry = false; - let mut i = 0; - while i < range { - let (sum, overflow) = digit::$Digit::carrying_add(self.digit(i + start), rhs.digits[i], carry); - self.set_digit(i + start, sum); - carry = overflow; - i += 1; - } - if carry { - self.set_digit(range + start, self.digit(range + start).wrapping_add(1)); // we use wrapping_add here, not regular addition as a carry will always occur to the left of self.digit(range + start) - } - } - } - } - - #[derive(Clone, Copy)] - struct Mul { - last: $Digit, - rest: [$Digit; M], - } - impl Mul { - const fn new(uint: $BUint, rhs: $Digit) -> Self { - let mut rest = [0; M]; - let mut carry: $Digit = 0; - let mut i = 0; - while i < M { - let (prod, c) = digit::$Digit::carrying_mul(uint.digits[i], rhs, carry, 0); - carry = c; - rest[i] = prod; - i += 1; - } - Self { - last: carry, - rest, - } - } - const fn digit(&self, index: usize) -> $Digit { - if index == M { - self.last - } else { - self.rest[index] - } - } - } - - let v_n_m1 = v.digits[n - 1]; - let v_n_m2 = v.digits[n - 2]; - - let mut u = Remainder::new(self, shift); - - let mut j = m + 1; // D2 - while j > 0 { - j -= 1; // D7 - - let u_jn = u.digit(j + n); - - #[inline] - const fn tuple_gt(a: ($Digit, $Digit), b: ($Digit, $Digit)) -> bool { - a.1 > b.1 || a.1 == b.1 && a.0 > b.0 - } - - // q_hat will be either `q` or `q + 1` - let mut q_hat = if u_jn < v_n_m1 { - let (mut q_hat, r_hat) = digit::$Digit::div_rem_wide(u.digit(j + n - 1), u_jn, v_n_m1); // D3 - - if tuple_gt(digit::$Digit::widening_mul(q_hat, v_n_m2), (u.digit(j + n - 2), r_hat as $Digit)) { - q_hat -= 1; - - if let Some(r_hat) = r_hat.checked_add(v_n_m1) { // this checks if `r_hat <= b`, where `b` is the digit base - if tuple_gt(digit::$Digit::widening_mul(q_hat, v_n_m2), (u.digit(j + n - 2), r_hat as $Digit)) { - q_hat -= 1; - } - } - } - q_hat - } else { - // `u[j + n - 1] >= v[n - 1]` so we know that estimate for q_hat would be larger than `Digit::MAX`. This is either equal to `q` or `q + 1` (very unlikely to be `q + 1`). - $Digit::MAX - }; - let overflow = u.sub(Mul::new(v, q_hat), j, n); // D4 - - if overflow { // D5 - unlikely, probability of this being true is ~ 2 / b where b is the digit base (i.e. `Digit::MAX`) - q_hat -= 1; - u.add(v, j, n); - } - q.digits[j] = q_hat; - } - (q, u.shr(shift)) - } - - #[inline] - pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) { - use core::cmp::Ordering; - - if self.is_zero() { - return (Self::ZERO, Self::ZERO); - } - - match self.cmp(&rhs) { - Ordering::Less => (Self::ZERO, self), - Ordering::Equal => (Self::ONE, Self::ZERO), - Ordering::Greater => { - let ldi = rhs.last_digit_index(); - if ldi == 0 { - let (div, rem) = self.div_rem_digit(rhs.digits[0]); - (div, Self::from_digit(rem)) - } else { - self.basecase_div_rem(rhs, ldi + 1) - } - } - } - } - - #[inline] - pub(crate) const fn div_rem(self, rhs: Self) -> (Self, Self) { - if rhs.is_zero() { - div_zero!() - } else { - self.div_rem_unchecked(rhs) - } - } - - #[doc = doc::checked::checked_div!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if rhs.is_zero() { - None - } else { - Some(self.div_rem_unchecked(rhs).0) - } - } - - #[doc = doc::checked::checked_div_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - self.checked_div(rhs) - } - - #[doc = doc::checked::checked_rem!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if rhs.is_zero() { - None - } else { - Some(self.div_rem_unchecked(rhs).1) - } - } - - #[doc = doc::checked::checked_rem_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - self.checked_rem(rhs) - } - } - - #[doc = doc::checked::checked_neg!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_neg(self) -> Option { - if self.is_zero() { - Some(self) - } else { - None - } - } - - const_fns! { - #[doc = doc::checked::checked_shl!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_shl(self, rhs: ExpType) -> Option { - if rhs >= Self::BITS { - None - } else { - unsafe { - Some(Self::unchecked_shl_internal(self, rhs)) - } - } - } - - #[doc = doc::checked::checked_shr!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_shr(self, rhs: ExpType) -> Option { - if rhs >= Self::BITS { - None - } else { - unsafe { - Some(Self::unchecked_shr_internal(self, rhs)) - } - } - } - } - - #[doc = doc::checked::checked_pow!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_pow(mut self, mut pow: ExpType) -> Option { - // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method - if pow == 0 { - return Some(Self::ONE); - } - let mut y = Self::ONE; - while pow > 1 { - if pow & 1 == 1 { - y = match self.checked_mul(y) { - Some(m) => m, - None => return None, - }; - } - self = match self.checked_mul(self) { - Some(m) => m, - None => return None, - }; - pow >>= 1; - } - self.checked_mul(y) - } - - #[doc = doc::checked::checked_ilog2!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_ilog2(self) -> Option { - self.bits().checked_sub(1) - } - - const_fns! { - #[inline] - const fn iilog(m: ExpType, b: Self, k: Self) -> (ExpType, Self) { - // https://people.csail.mit.edu/jaffer/III/iilog.pdf - if b.gt(k) { - (m, k) - } else { - let (new, q) = Self::iilog(m << 1, b.mul(b), k.div_rem_unchecked(b).0); - if b.gt(q) { - (new, q) - } else { - (new + m, q.div(b)) - } - } - } - - #[doc = doc::checked::checked_ilog10!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_ilog10(self) -> Option { - if self.is_zero() { - return None; - } - if Self::TEN.gt(self) { - return Some(0); - } - Some(Self::iilog(1, Self::TEN, self.div_rem_digit(10).0).0) - } - - #[doc = doc::checked::checked_ilog!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_ilog(self, base: Self) -> Option { - use core::cmp::Ordering; - match base.cmp(&Self::TWO) { - Ordering::Less => None, - Ordering::Equal => self.checked_ilog2(), - Ordering::Greater => { - if self.is_zero() { - return None; - } - if base.gt(self) { - return Some(0); - } - Some(Self::iilog(1, base, self.div(base)).0) - } - } - } - - #[doc = doc::checked::checked_next_multiple_of!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { - match self.checked_rem(rhs) { - Some(rem) => { - if rem.is_zero() { - // `rhs` divides `self` exactly so just return `self` - Some(self) - } else { - // `next_multiple = floor(self / rhs) * rhs + rhs = (self - rem) + rhs` - self.checked_add(rhs.sub(rem)) - } - }, - None => None, - } - } - } - - #[doc = doc::checked::checked_next_power_of_two!(U 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_next_power_of_two(self) -> Option { - if self.is_power_of_two() { - return Some(self); - } - let bits = self.bits(); - if bits == Self::BITS { - return None; - } - Some(Self::power_of_two(bits)) - } - } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::{test_bignum, types::*}; - - test_bignum! { - function: ::checked_add(a: utest, b: utest), - cases: [ - (utest::MAX, 1u8) - ] - } - test_bignum! { - function: ::checked_add_signed(a: utest, b: itest) - } - test_bignum! { - function: ::checked_sub(a: utest, b: utest) - } - test_bignum! { - function: ::checked_mul(a: utest, b: utest) - } - test_bignum! { - function: ::checked_div(a: utest, b: utest), - cases: [ - (328622u32 as utest, 10000u32 as utest), // tests the unlikely condition in the division algorithm at step D5 - (2074086u32 as utest, 76819u32 as utest) // tests the unlikely condition in the division algorithm at step D5 - ] - } - test_bignum! { - function: ::checked_div_euclid(a: utest, b: utest) - } - test_bignum! { - function: ::checked_rem(a: utest, b: utest) - } - test_bignum! { - function: ::checked_rem_euclid(a: utest, b: utest) - } - test_bignum! { - function: ::checked_neg(a: utest) - } - test_bignum! { - function: ::checked_shl(a: utest, b: u16) - } - test_bignum! { - function: ::checked_shr(a: utest, b: u16) - } - test_bignum! { - function: ::checked_pow(a: utest, b: u16) - } - test_bignum! { - function: ::checked_ilog(a: utest, b: utest), - cases: [ - (2u8, 60u8) - ] - } - test_bignum! { - function: ::checked_ilog2(a: utest) - } - test_bignum! { - function: ::checked_ilog10(a: utest) - } - test_bignum! { - function: ::checked_next_power_of_two(a: utest), - cases: [ - (utest::MAX) - ] - } - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[doc = doc::checked::impl_desc!()] + impl $BUint { + #[doc = doc::checked::checked_add!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_add(self, rhs: Self) -> Option { + tuple_to_option(self.overflowing_add(rhs)) + } + + #[doc = doc::checked::checked_add_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_add_signed(self, rhs: $BInt) -> Option { + tuple_to_option(self.overflowing_add_signed(rhs)) + } + + #[doc = doc::checked::checked_sub!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_sub(self, rhs: Self) -> Option { + tuple_to_option(self.overflowing_sub(rhs)) + } + + #[doc = doc::checked::checked_mul!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_mul(self, rhs: Self) -> Option { + tuple_to_option(self.overflowing_mul(rhs)) + } + + crate::nightly::const_fns! { + pub(crate) const fn div_rem_digit(self, rhs: $Digit) -> (Self, $Digit) { + let mut out = Self::ZERO; + let mut rem: $Digit = 0; + let mut i = N; + while i > 0 { + i -= 1; + let (q, r) = digit::$Digit::div_rem_wide(self.digits[i], rem, rhs); + rem = r; + out.digits[i] = q; + } + (out, rem) + } + const fn basecase_div_rem(self, mut v: Self, n: usize) -> (Self, Self) { + // The Art of Computer Programming Volume 2 by Donald Knuth, Section 4.3.1, Algorithm D + + let mut q = Self::ZERO; + let m = self.last_digit_index() + 1 - n; + let shift = v.digits[n - 1].leading_zeros() as ExpType; + + v = unsafe { + Self::unchecked_shl_internal(v, shift) + }; // D1 + + struct Remainder { + first: $Digit, + rest: [$Digit; M], + } + impl Remainder { + const fn digit(&self, index: usize) -> $Digit { + if index == 0 { + self.first + } else { + self.rest[index - 1] + } + } + const fn shr(self, shift: ExpType) -> $BUint { + let mut out = $BUint::ZERO; + let mut i = 0; + while i < M { + out.digits[i] = self.digit(i) >> shift; + i += 1; + } + if shift > 0 { + i = 0; + while i < M { + out.digits[i] |= self.rest[i] << (digit::$Digit::BITS as ExpType - shift); + i += 1; + } + } + out + } + crate::nightly::const_fns! { + const fn new(uint: $BUint, shift: ExpType) -> Self { + let first = uint.digits[0] << shift; + let rest = uint.wrapping_shr(digit::$Digit::BITS - shift); + Self { + first, + rest: rest.digits, + } + } + const fn set_digit(&mut self, index: usize, digit: $Digit) -> () { + if index == 0 { + self.first = digit; + } else { + self.rest[index - 1] = digit; + } + } + const fn sub(&mut self, rhs: Mul, start: usize, range: usize) -> bool { + let mut borrow = false; + let mut i = 0; + while i <= range { + let (sub, overflow) = digit::$Digit::borrowing_sub(self.digit(i + start), rhs.digit(i), borrow); + self.set_digit(i + start, sub); + borrow = overflow; + i += 1; + } + borrow + } + const fn add(&mut self, rhs: $BUint, start: usize, range: usize) -> () { + let mut carry = false; + let mut i = 0; + while i < range { + let (sum, overflow) = digit::$Digit::carrying_add(self.digit(i + start), rhs.digits[i], carry); + self.set_digit(i + start, sum); + carry = overflow; + i += 1; + } + if carry { + self.set_digit(range + start, self.digit(range + start).wrapping_add(1)); // we use wrapping_add here, not regular addition as a carry will always occur to the left of self.digit(range + start) + } + } + } + } + + #[derive(Clone, Copy)] + struct Mul { + last: $Digit, + rest: [$Digit; M], + } + impl Mul { + const fn new(uint: $BUint, rhs: $Digit) -> Self { + let mut rest = [0; M]; + let mut carry: $Digit = 0; + let mut i = 0; + while i < M { + let (prod, c) = digit::$Digit::carrying_mul(uint.digits[i], rhs, carry, 0); + carry = c; + rest[i] = prod; + i += 1; + } + Self { + last: carry, + rest, + } + } + const fn digit(&self, index: usize) -> $Digit { + if index == M { + self.last + } else { + self.rest[index] + } + } + } + + let v_n_m1 = v.digits[n - 1]; + let v_n_m2 = v.digits[n - 2]; + + let mut u = Remainder::new(self, shift); + + let mut j = m + 1; // D2 + while j > 0 { + j -= 1; // D7 + + let u_jn = u.digit(j + n); + + #[inline] + const fn tuple_gt(a: ($Digit, $Digit), b: ($Digit, $Digit)) -> bool { + a.1 > b.1 || a.1 == b.1 && a.0 > b.0 + } + + // q_hat will be either `q` or `q + 1` + let mut q_hat = if u_jn < v_n_m1 { + let (mut q_hat, r_hat) = digit::$Digit::div_rem_wide(u.digit(j + n - 1), u_jn, v_n_m1); // D3 + + if tuple_gt(digit::$Digit::widening_mul(q_hat, v_n_m2), (u.digit(j + n - 2), r_hat as $Digit)) { + q_hat -= 1; + + if let Some(r_hat) = r_hat.checked_add(v_n_m1) { // this checks if `r_hat <= b`, where `b` is the digit base + if tuple_gt(digit::$Digit::widening_mul(q_hat, v_n_m2), (u.digit(j + n - 2), r_hat as $Digit)) { + q_hat -= 1; + } + } + } + q_hat + } else { + // `u[j + n - 1] >= v[n - 1]` so we know that estimate for q_hat would be larger than `Digit::MAX`. This is either equal to `q` or `q + 1` (very unlikely to be `q + 1`). + $Digit::MAX + }; + let overflow = u.sub(Mul::new(v, q_hat), j, n); // D4 + + if overflow { // D5 - unlikely, probability of this being true is ~ 2 / b where b is the digit base (i.e. `Digit::MAX`) + q_hat -= 1; + u.add(v, j, n); + } + q.digits[j] = q_hat; + } + (q, u.shr(shift)) + } + + #[inline] + pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) { + use core::cmp::Ordering; + + if self.is_zero() { + return (Self::ZERO, Self::ZERO); + } + + match self.cmp(&rhs) { + Ordering::Less => (Self::ZERO, self), + Ordering::Equal => (Self::ONE, Self::ZERO), + Ordering::Greater => { + let ldi = rhs.last_digit_index(); + if ldi == 0 { + let (div, rem) = self.div_rem_digit(rhs.digits[0]); + (div, Self::from_digit(rem)) + } else { + self.basecase_div_rem(rhs, ldi + 1) + } + } + } + } + + #[inline] + pub(crate) const fn div_rem(self, rhs: Self) -> (Self, Self) { + if rhs.is_zero() { + div_zero!() + } else { + self.div_rem_unchecked(rhs) + } + } + + #[doc = doc::checked::checked_div!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if rhs.is_zero() { + None + } else { + Some(self.div_rem_unchecked(rhs).0) + } + } + + #[doc = doc::checked::checked_div_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + self.checked_div(rhs) + } + + #[doc = doc::checked::checked_rem!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if rhs.is_zero() { + None + } else { + Some(self.div_rem_unchecked(rhs).1) + } + } + + #[doc = doc::checked::checked_rem_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + self.checked_rem(rhs) + } + } + + #[doc = doc::checked::checked_neg!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_neg(self) -> Option { + if self.is_zero() { + Some(self) + } else { + None + } + } + + #[doc = doc::checked::checked_shl!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_shl(self, rhs: ExpType) -> Option { + if rhs >= Self::BITS { + None + } else { + unsafe { + Some(Self::unchecked_shl_internal(self, rhs)) + } + } + } + + #[doc = doc::checked::checked_shr!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_shr(self, rhs: ExpType) -> Option { + if rhs >= Self::BITS { + None + } else { + unsafe { + Some(Self::unchecked_shr_internal(self, rhs)) + } + } + } + + #[doc = doc::checked::checked_pow!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_pow(mut self, mut pow: ExpType) -> Option { + // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method + if pow == 0 { + return Some(Self::ONE); + } + let mut y = Self::ONE; + while pow > 1 { + if pow & 1 == 1 { + y = match self.checked_mul(y) { + Some(m) => m, + None => return None, + }; + } + self = match self.checked_mul(self) { + Some(m) => m, + None => return None, + }; + pow >>= 1; + } + self.checked_mul(y) + } + + #[doc = doc::checked::checked_ilog2!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_ilog2(self) -> Option { + self.bits().checked_sub(1) + } + + crate::nightly::const_fns! { + #[inline] + const fn iilog(m: ExpType, b: Self, k: Self) -> (ExpType, Self) { + // https://people.csail.mit.edu/jaffer/III/iilog.pdf + if b.gt(k) { + (m, k) + } else { + let (new, q) = Self::iilog(m << 1, b.mul(b), k.div_rem_unchecked(b).0); + if b.gt(q) { + (new, q) + } else { + (new + m, q.div(b)) + } + } + } + + #[doc = doc::checked::checked_ilog10!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_ilog10(self) -> Option { + if self.is_zero() { + return None; + } + if Self::TEN.gt(self) { + return Some(0); + } + Some(Self::iilog(1, Self::TEN, self.div_rem_digit(10).0).0) + } + + #[doc = doc::checked::checked_ilog!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_ilog(self, base: Self) -> Option { + use core::cmp::Ordering; + match base.cmp(&Self::TWO) { + Ordering::Less => None, + Ordering::Equal => self.checked_ilog2(), + Ordering::Greater => { + if self.is_zero() { + return None; + } + if base.gt(self) { + return Some(0); + } + Some(Self::iilog(1, base, self.div(base)).0) + } + } + } + + #[doc = doc::checked::checked_next_multiple_of!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { + match self.checked_rem(rhs) { + Some(rem) => { + if rem.is_zero() { + // `rhs` divides `self` exactly so just return `self` + Some(self) + } else { + // `next_multiple = floor(self / rhs) * rhs + rhs = (self - rem) + rhs` + self.checked_add(rhs.sub(rem)) + } + }, + None => None, + } + } + } + + #[doc = doc::checked::checked_next_power_of_two!(U 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_next_power_of_two(self) -> Option { + if self.is_power_of_two() { + return Some(self); + } + let bits = self.bits(); + if bits == Self::BITS { + return None; + } + Some(Self::power_of_two(bits)) + } + } + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::{test_bignum, types::*}; + + test_bignum! { + function: ::checked_add(a: utest, b: utest), + cases: [ + (utest::MAX, 1u8) + ] + } + test_bignum! { + function: ::checked_add_signed(a: utest, b: itest) + } + test_bignum! { + function: ::checked_sub(a: utest, b: utest) + } + test_bignum! { + function: ::checked_mul(a: utest, b: utest) + } + test_bignum! { + function: ::checked_div(a: utest, b: utest), + cases: [ + (328622u32 as utest, 10000u32 as utest), // tests the unlikely condition in the division algorithm at step D5 + (2074086u32 as utest, 76819u32 as utest) // tests the unlikely condition in the division algorithm at step D5 + ] + } + test_bignum! { + function: ::checked_div_euclid(a: utest, b: utest) + } + test_bignum! { + function: ::checked_rem(a: utest, b: utest) + } + test_bignum! { + function: ::checked_rem_euclid(a: utest, b: utest) + } + test_bignum! { + function: ::checked_neg(a: utest) + } + test_bignum! { + function: ::checked_shl(a: utest, b: u16) + } + test_bignum! { + function: ::checked_shr(a: utest, b: u16) + } + test_bignum! { + function: ::checked_pow(a: utest, b: u16) + } + test_bignum! { + function: ::checked_ilog(a: utest, b: utest), + cases: [ + (2u8, 60u8) + ] + } + test_bignum! { + function: ::checked_ilog2(a: utest) + } + test_bignum! { + function: ::checked_ilog10(a: utest) + } + test_bignum! { + function: ::checked_next_power_of_two(a: utest), + cases: [ + (utest::MAX) + ] + } + } + } + }; } crate::macro_impl!(checked); diff --git a/src/buint/cmp.rs b/src/buint/cmp.rs index ad31042..362ee76 100644 --- a/src/buint/cmp.rs +++ b/src/buint/cmp.rs @@ -3,16 +3,16 @@ use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; macro_rules! cmp { ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl_const! { + impl_const! { impl const PartialEq for $BUint { #[inline] fn eq(&self, other: &Self) -> bool { - Self::eq(self, other) + Self::eq(self, other) } } } - impl Eq for $BUint {} + impl Eq for $BUint {} impl_const! { impl const PartialOrd for $BUint { @@ -25,32 +25,32 @@ macro_rules! cmp { impl_const! { impl const Ord for $BUint { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - Self::cmp(self, other) - } - - #[inline] - fn max(self, other: Self) -> Self { - Self::max(self, other) - } - - #[inline] - fn min(self, other: Self) -> Self { - Self::min(self, other) - } - - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - Self::clamp(self, min, max) - } + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Self::cmp(self, other) + } + + #[inline] + fn max(self, other: Self) -> Self { + Self::max(self, other) + } + + #[inline] + fn min(self, other: Self) -> Self { + Self::min(self, other) + } + + #[inline] + fn clamp(self, min: Self, max: Self) -> Self { + Self::clamp(self, min, max) + } } } #[cfg(test)] paste::paste! { mod [<$Digit _digit_tests>] { use crate::test::types::big_types::$Digit::*; - crate::int::cmp::tests!(utest); + crate::int::cmp::tests!(utest); } } }; diff --git a/src/buint/const_trait_fillers.rs b/src/buint/const_trait_fillers.rs index 9cdaf3c..dbc35d3 100644 --- a/src/buint/const_trait_fillers.rs +++ b/src/buint/const_trait_fillers.rs @@ -1,110 +1,110 @@ -use core::cmp::Ordering; -use crate::ExpType; use crate::doc; +use crate::ExpType; +use core::cmp::Ordering; macro_rules! const_trait_fillers { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::const_trait_fillers::impl_desc!()] - impl $BUint { - #[inline] - pub const fn bitand(self, rhs: Self) -> Self { - let mut out = Self::ZERO; - let mut i = 0; - while i < N { - out.digits[i] = self.digits[i] & rhs.digits[i]; - i += 1; - } - out - } + ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[doc = doc::const_trait_fillers::impl_desc!()] + impl $BUint { + #[inline] + pub const fn bitand(self, rhs: Self) -> Self { + let mut out = Self::ZERO; + let mut i = 0; + while i < N { + out.digits[i] = self.digits[i] & rhs.digits[i]; + i += 1; + } + out + } + + #[inline] + pub const fn bitor(self, rhs: Self) -> Self { + let mut out = Self::ZERO; + let mut i = 0; + while i < N { + out.digits[i] = self.digits[i] | rhs.digits[i]; + i += 1; + } + out + } - #[inline] - pub const fn bitor(self, rhs: Self) -> Self { - let mut out = Self::ZERO; - let mut i = 0; - while i < N { - out.digits[i] = self.digits[i] | rhs.digits[i]; - i += 1; - } - out - } + #[inline] + pub const fn bitxor(self, rhs: Self) -> Self { + let mut out = Self::ZERO; + let mut i = 0; + while i < N { + out.digits[i] = self.digits[i] ^ rhs.digits[i]; + i += 1; + } + out + } - #[inline] - pub const fn bitxor(self, rhs: Self) -> Self { - let mut out = Self::ZERO; - let mut i = 0; - while i < N { - out.digits[i] = self.digits[i] ^ rhs.digits[i]; - i += 1; - } - out - } + #[inline] + pub const fn not(self) -> Self { + let mut out = Self::ZERO; + let mut i = 0; + while i < N { + out.digits[i] = !self.digits[i]; + i += 1; + } + out + } - #[inline] - pub const fn not(self) -> Self { - let mut out = Self::ZERO; - let mut i = 0; - while i < N { - out.digits[i] = !self.digits[i]; - i += 1; - } - out - } - - #[inline] - pub const fn eq(&self, other: &Self) -> bool { - let mut i = 0; - while i < N { - if self.digits[i] != other.digits[i] { - return false; - } - i += 1; - } - true - } + #[inline] + pub const fn eq(&self, other: &Self) -> bool { + let mut i = 0; + while i < N { + if self.digits[i] != other.digits[i] { + return false; + } + i += 1; + } + true + } - #[inline] - pub const fn ne(&self, other: &Self) -> bool { - !Self::eq(self, other) - } + #[inline] + pub const fn ne(&self, other: &Self) -> bool { + !Self::eq(self, other) + } - #[inline] - pub const fn cmp(&self, other: &Self) -> Ordering { - let mut i = N; - while i > 0 { - i -= 1; - let a = self.digits[i]; - let b = other.digits[i]; + #[inline] + pub const fn cmp(&self, other: &Self) -> Ordering { + let mut i = N; + while i > 0 { + i -= 1; + let a = self.digits[i]; + let b = other.digits[i]; - // Clippy: don't use match here as `cmp` is not yet const for primitive integers - #[allow(clippy::comparison_chain)] - if a > b { - return Ordering::Greater; - } else if a < b { - return Ordering::Less; - } - } - Ordering::Equal - } + // Clippy: don't use match here as `cmp` is not yet const for primitive integers + #[allow(clippy::comparison_chain)] + if a > b { + return Ordering::Greater; + } else if a < b { + return Ordering::Less; + } + } + Ordering::Equal + } - crate::int::cmp::impls!(); + crate::int::cmp::impls!(); - crate::int::ops::trait_fillers!(); + crate::int::ops::trait_fillers!(); - crate::nightly::const_fn! { - #[inline] - pub const fn div(self, rhs: Self) -> Self { - self.wrapping_div(rhs) - } - } + crate::nightly::const_fn! { + #[inline] + pub const fn div(self, rhs: Self) -> Self { + self.wrapping_div(rhs) + } + } - crate::nightly::const_fn! { - #[inline] - pub const fn rem(self, rhs: Self) -> Self { - self.wrapping_rem(rhs) - } - } - } - }; + crate::nightly::const_fn! { + #[inline] + pub const fn rem(self, rhs: Self) -> Self { + self.wrapping_rem(rhs) + } + } + } + }; } -crate::macro_impl!(const_trait_fillers); \ No newline at end of file +crate::macro_impl!(const_trait_fillers); diff --git a/src/buint/consts.rs b/src/buint/consts.rs index 767da47..8fda9e2 100644 --- a/src/buint/consts.rs +++ b/src/buint/consts.rs @@ -1,10 +1,10 @@ macro_rules! pos_const { - ($($name: ident $num: literal), *) => { - $( - #[doc = doc::consts::value_desc!($num)] - pub const $name: Self = Self::from_digit($num); - )* - } + ($($name: ident $num: literal), *) => { + $( + #[doc = doc::consts::value_desc!($num)] + pub const $name: Self = Self::from_digit($num); + )* + } } use crate::digit; @@ -12,27 +12,27 @@ use crate::doc; use crate::ExpType; macro_rules! consts { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::consts::impl_desc!()] - impl $BUint { - #[doc = doc::consts::min!(U 512)] - pub const MIN: Self = Self::from_digits([$Digit::MIN; N]); + ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[doc = doc::consts::impl_desc!()] + impl $BUint { + #[doc = doc::consts::min!(U 512)] + pub const MIN: Self = Self::from_digits([$Digit::MIN; N]); - #[doc = doc::consts::max!(U 512)] - pub const MAX: Self = Self::from_digits([$Digit::MAX; N]); + #[doc = doc::consts::max!(U 512)] + pub const MAX: Self = Self::from_digits([$Digit::MAX; N]); - #[doc = doc::consts::bits!(U 512, 512)] - pub const BITS: ExpType = digit::$Digit::BITS * N as ExpType; + #[doc = doc::consts::bits!(U 512, 512)] + pub const BITS: ExpType = digit::$Digit::BITS * N as ExpType; - #[doc = doc::consts::bytes!(U 512, 512)] - pub const BYTES: ExpType = Self::BITS / 8; + #[doc = doc::consts::bytes!(U 512, 512)] + pub const BYTES: ExpType = Self::BITS / 8; - #[doc = doc::consts::zero!(U 512)] - pub const ZERO: Self = Self::MIN; + #[doc = doc::consts::zero!(U 512)] + pub const ZERO: Self = Self::MIN; - pos_const!(ONE 1, TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10); - } - }; + pos_const!(ONE 1, TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10); + } + }; } crate::macro_impl!(consts); diff --git a/src/buint/convert.rs b/src/buint/convert.rs index 400570d..6963d67 100644 --- a/src/buint/convert.rs +++ b/src/buint/convert.rs @@ -1,91 +1,91 @@ macro_rules! from_uint { - ($BUint: ident, $Digit: ident; $($uint: tt),*) => { - $(impl_const! { - impl const From<$uint> for $BUint { - #[inline] - fn from(int: $uint) -> Self { - const UINT_BITS: usize = $uint::BITS as usize; - let mut out = Self::ZERO; - let mut i = 0; - while i << crate::digit::$Digit::BIT_SHIFT < UINT_BITS { - let d = (int >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit; - if d != 0 { - out.digits[i] = d; - } - i += 1; - } - out - } - } - })* - } + ($BUint: ident, $Digit: ident; $($uint: tt),*) => { + $(impl_const! { + impl const From<$uint> for $BUint { + #[inline] + fn from(int: $uint) -> Self { + const UINT_BITS: usize = $uint::BITS as usize; + let mut out = Self::ZERO; + let mut i = 0; + while i << crate::digit::$Digit::BIT_SHIFT < UINT_BITS { + let d = (int >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit; + if d != 0 { + out.digits[i] = d; + } + i += 1; + } + out + } + } + })* + } } macro_rules! try_from_iint { - ($BUint: ident; $($int: tt -> $uint: tt),*) => { - $(impl_const! { - impl const TryFrom<$int> for $BUint { - type Error = TryFromIntError; - - #[inline] - fn try_from(int: $int) -> Result { - if int.is_negative() { - return Err(TryFromIntError(())); - } - let bits = int as $uint; - Ok(Self::from(bits)) - } - } - })* - } + ($BUint: ident; $($int: tt -> $uint: tt),*) => { + $(impl_const! { + impl const TryFrom<$int> for $BUint { + type Error = TryFromIntError; + + #[inline] + fn try_from(int: $int) -> Result { + if int.is_negative() { + return Err(TryFromIntError(())); + } + let bits = int as $uint; + Ok(Self::from(bits)) + } + } + })* + } } macro_rules! try_from_buint { - ($BUint: ident, $Digit: ident; $($int: ty), *) => { - $(crate::nightly::impl_const! { - impl const TryFrom<$BUint> for $int { - type Error = TryFromIntError; - - #[inline] - fn try_from(u: $BUint) -> Result<$int, Self::Error> { - let mut out = 0; - let mut i = 0; - if $Digit::BITS > <$int>::BITS { - let small = u.digits[i] as $int; - let trunc = small as $Digit; - if u.digits[i] != trunc { - return Err(TryFromIntError(())); - } - out = small; - i = 1; - } else { - loop { - let shift = i << crate::digit::$Digit::BIT_SHIFT; - if i >= N || shift >= <$int>::BITS as usize { - break; - } - out |= u.digits[i] as $int << shift; - i += 1; - } - } - - #[allow(unused_comparisons)] - if out < 0 { - return Err(TryFromIntError(())); - } - - while i < N { - if u.digits[i] != 0 { - return Err(TryFromIntError(())); - } - i += 1; - } - - Ok(out) - } - } - })* - }; + ($BUint: ident, $Digit: ident; $($int: ty), *) => { + $(crate::nightly::impl_const! { + impl const TryFrom<$BUint> for $int { + type Error = TryFromIntError; + + #[inline] + fn try_from(u: $BUint) -> Result<$int, Self::Error> { + let mut out = 0; + let mut i = 0; + if $Digit::BITS > <$int>::BITS { + let small = u.digits[i] as $int; + let trunc = small as $Digit; + if u.digits[i] != trunc { + return Err(TryFromIntError(())); + } + out = small; + i = 1; + } else { + loop { + let shift = i << crate::digit::$Digit::BIT_SHIFT; + if i >= N || shift >= <$int>::BITS as usize { + break; + } + out |= u.digits[i] as $int << shift; + i += 1; + } + } + + #[allow(unused_comparisons)] + if out < 0 { + return Err(TryFromIntError(())); + } + + while i < N { + if u.digits[i] != 0 { + return Err(TryFromIntError(())); + } + i += 1; + } + + Ok(out) + } + } + })* + }; } use crate::cast::CastFrom; @@ -93,69 +93,69 @@ use crate::errors::TryFromIntError; use crate::nightly::impl_const; macro_rules! convert { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl_const! { - impl const From for $BUint { - #[inline] - fn from(small: bool) -> Self { - Self::cast_from(small) - } - } - } - - impl_const! { - impl const From for $BUint { - #[inline] - fn from(c: char) -> Self { - Self::cast_from(c) - } - } - } - - from_uint!($BUint, $Digit; u8, u16, u32, u64, u128, usize); - // TODO: decide whether it should be TryFrom or From, same for $BInt - - try_from_iint!($BUint; i8 -> u8, i16 -> u16, i32 -> u32, isize -> usize, i64 -> u64, i128 -> u128); - - try_from_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - - impl_const! { - impl const From<[$Digit; N]> for $BUint { - #[inline] - fn from(digits: [$Digit; N]) -> Self { - Self::from_digits(digits) - } - } - } - - impl_const! { - impl const From<$BUint> for [$Digit; N] { - #[inline] - fn from(uint: $BUint) -> Self { - uint.digits - } - } - } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::{self, types::utest}; - - // We can test with `TryFrom` for all types as `TryFrom` is automatically implemented when `From` is implemented - test::test_from! { - function: ::try_from, - from_types: (u8, u16, u32, u64, bool, char, i8, i16, i32, i64, isize, usize) - } - - test::test_into! { - function: ::try_into, - into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize) - } - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + impl_const! { + impl const From for $BUint { + #[inline] + fn from(small: bool) -> Self { + Self::cast_from(small) + } + } + } + + impl_const! { + impl const From for $BUint { + #[inline] + fn from(c: char) -> Self { + Self::cast_from(c) + } + } + } + + from_uint!($BUint, $Digit; u8, u16, u32, u64, u128, usize); + // TODO: decide whether it should be TryFrom or From, same for $BInt + + try_from_iint!($BUint; i8 -> u8, i16 -> u16, i32 -> u32, isize -> usize, i64 -> u64, i128 -> u128); + + try_from_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + + impl_const! { + impl const From<[$Digit; N]> for $BUint { + #[inline] + fn from(digits: [$Digit; N]) -> Self { + Self::from_digits(digits) + } + } + } + + impl_const! { + impl const From<$BUint> for [$Digit; N] { + #[inline] + fn from(uint: $BUint) -> Self { + uint.digits + } + } + } + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::{self, types::utest}; + + // We can test with `TryFrom` for all types as `TryFrom` is automatically implemented when `From` is implemented + test::test_from! { + function: ::try_from, + from_types: (u8, u16, u32, u64, bool, char, i8, i16, i32, i64, isize, usize) + } + + test::test_into! { + function: ::try_into, + into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize) + } + } + } + }; } crate::macro_impl!(convert); diff --git a/src/buint/endian.rs b/src/buint/endian.rs index 07fcc2d..bed8150 100644 --- a/src/buint/endian.rs +++ b/src/buint/endian.rs @@ -3,305 +3,303 @@ use crate::doc; use core::mem::MaybeUninit; macro_rules! endian { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::endian::impl_desc!($BUint)] - impl $BUint { - #[doc = doc::endian::from_be!(U 256)] - #[must_use] - #[inline] - pub const fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - return x; - #[cfg(not(target_endian = "big"))] - x.swap_bytes() - } + ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[doc = doc::endian::impl_desc!($BUint)] + impl $BUint { + #[doc = doc::endian::from_be!(U 256)] + #[must_use] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + return x; + #[cfg(not(target_endian = "big"))] + x.swap_bytes() + } - #[doc = doc::endian::from_le!(U 256)] - #[must_use] - #[inline] - pub const fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - return x; - #[cfg(not(target_endian = "little"))] - x.swap_bytes() - } + #[doc = doc::endian::from_le!(U 256)] + #[must_use] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + return x; + #[cfg(not(target_endian = "little"))] + x.swap_bytes() + } - #[doc = doc::endian::to_be!(U 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_be(self) -> Self { - Self::from_be(self) - } + #[doc = doc::endian::to_be!(U 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_be(self) -> Self { + Self::from_be(self) + } - #[doc = doc::endian::to_le!(U 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_le(self) -> Self { - Self::from_le(self) - } + #[doc = doc::endian::to_le!(U 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_le(self) -> Self { + Self::from_le(self) + } - crate::nightly::const_fns! { - /// Create an integer value from a slice of bytes in big endian. The value is wrapped in an `Option` as the integer represented by the slice of bytes may represent an integer too large to be represented by the type. - /// - /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros at the start so that it's length equals `Self::BYTES`. - /// - /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless leading zeros from the slice can be removed until the length of the slice equals `Self::BYTES`. - /// - /// # Examples - /// - /// ``` - /// // NB: This example requires the `nightly` feature to use the `from_be_bytes` method. - /// use bnum::types::U128; - /// - /// let value_from_array = U128::from(u128::from_be_bytes([0, 0, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12])); // using the `from_be_bytes` method on the primitve `u128` here instead of on `U128` as `from_be_bytes` is currently only available in bnum on nightly - /// let value_from_slice = U128::from_be_slice(&[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]).unwrap(); - /// let value_from_long_slice = U128::from_be_slice(&[0, 0, 0, 0, 0, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]).unwrap(); - /// - /// assert_eq!(value_from_array, value_from_slice); - /// assert_eq!(value_from_array, value_from_long_slice); - /// - /// let invalid_slice = &[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90]; - /// assert_eq!(U128::from_be_slice(invalid_slice), None); - /// ``` - #[must_use] - pub const fn from_be_slice(slice: &[u8]) -> Option { - let len = slice.len(); - let mut out = Self::ZERO; - let slice_ptr = slice.as_ptr(); - let mut i = 0; - let exact = len >> digit::$Digit::BYTE_SHIFT; - while i < exact { - let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); - let ptr = uninit.as_mut_ptr() as *mut u8; - let digit_bytes = unsafe { - slice_ptr - .add(len - digit::$Digit::BYTES as usize - (i << digit::$Digit::BYTE_SHIFT)) - .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); - uninit.assume_init() - }; - let digit = $Digit::from_be_bytes(digit_bytes); - if i < N { - out.digits[i] = digit; - } else if digit != 0 { - return None; - }; - i += 1; - } - let rem = len & (digit::$Digit::BYTES as usize - 1); - if rem == 0 { - Some(out) - } else { - let mut last_digit_bytes = [0; digit::$Digit::BYTES as usize]; - let mut j = 0; - while j < rem { - last_digit_bytes[digit::$Digit::BYTES as usize - rem + j] = slice[j]; - j += 1; - } - let digit = $Digit::from_be_bytes(last_digit_bytes); - if i < N { - out.digits[i] = digit; - } else if digit != 0 { - return None; - }; - Some(out) - } - } + /// Create an integer value from a slice of bytes in big endian. The value is wrapped in an `Option` as the integer represented by the slice of bytes may represent an integer too large to be represented by the type. + /// + /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros at the start so that it's length equals `Self::BYTES`. + /// + /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless leading zeros from the slice can be removed until the length of the slice equals `Self::BYTES`. + /// + /// # Examples + /// + /// ``` + /// // NB: This example requires the `nightly` feature to use the `from_be_bytes` method. + /// use bnum::types::U128; + /// + /// let value_from_array = U128::from(u128::from_be_bytes([0, 0, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12])); // using the `from_be_bytes` method on the primitve `u128` here instead of on `U128` as `from_be_bytes` is currently only available in bnum on nightly + /// let value_from_slice = U128::from_be_slice(&[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]).unwrap(); + /// let value_from_long_slice = U128::from_be_slice(&[0, 0, 0, 0, 0, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]).unwrap(); + /// + /// assert_eq!(value_from_array, value_from_slice); + /// assert_eq!(value_from_array, value_from_long_slice); + /// + /// let invalid_slice = &[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90]; + /// assert_eq!(U128::from_be_slice(invalid_slice), None); + /// ``` + #[must_use] + pub const fn from_be_slice(slice: &[u8]) -> Option { + let len = slice.len(); + let mut out = Self::ZERO; + let slice_ptr = slice.as_ptr(); + let mut i = 0; + let exact = len >> digit::$Digit::BYTE_SHIFT; + while i < exact { + let uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); + let ptr = uninit.as_ptr().cast_mut() as *mut u8; // TODO: can change to as_mut_ptr() when const_mut_refs is stabilised + let digit_bytes = unsafe { + slice_ptr + .add(len - digit::$Digit::BYTES as usize - (i << digit::$Digit::BYTE_SHIFT)) + .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); + uninit.assume_init() + }; + let digit = $Digit::from_be_bytes(digit_bytes); + if i < N { + out.digits[i] = digit; + } else if digit != 0 { + return None; + }; + i += 1; + } + let rem = len & (digit::$Digit::BYTES as usize - 1); + if rem == 0 { + Some(out) + } else { + let mut last_digit_bytes = [0; digit::$Digit::BYTES as usize]; + let mut j = 0; + while j < rem { + last_digit_bytes[digit::$Digit::BYTES as usize - rem + j] = slice[j]; + j += 1; + } + let digit = $Digit::from_be_bytes(last_digit_bytes); + if i < N { + out.digits[i] = digit; + } else if digit != 0 { + return None; + }; + Some(out) + } + } - /// Creates an integer value from a slice of bytes in little endian. The value is wrapped in an `Option` as the bytes may represent an integer too large to be represented by the type. - /// - /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros at the end so that it's length equals `Self::BYTES`. - /// - /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless trailing zeros from the slice can be removed until the length of the slice equals `Self::BYTES`. - /// - /// # Examples - /// - /// ``` - /// // NB: This example requires the `nightly` feature to use the `from_le_bytes` method. - /// use bnum::types::U128; - /// - /// let value_from_array = U128::from(u128::from_le_bytes([0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0, 0])); // using the `from_le_bytes` method on the primitve `u128` here instead of on `U128` as `from_le_bytes` is currently only available in bnum on nightly - /// let value_from_slice = U128::from_le_slice(&[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56]).unwrap(); - /// let value_from_long_slice = U128::from_le_slice(&[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0, 0, 0, 0, 0, 0]).unwrap(); - /// - /// assert_eq!(value_from_array, value_from_slice); - /// assert_eq!(value_from_array, value_from_long_slice); - /// - /// let invalid_slice = &[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90]; - /// assert_eq!(U128::from_le_slice(invalid_slice), None); - /// ``` - #[must_use] - pub const fn from_le_slice(slice: &[u8]) -> Option { - let len = slice.len(); - let mut out = Self::ZERO; - let slice_ptr = slice.as_ptr(); - let mut i = 0; - let exact = len >> digit::$Digit::BYTE_SHIFT; - while i < exact { - let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); - let ptr = uninit.as_mut_ptr() as *mut u8; - let digit_bytes = unsafe { - slice_ptr - .add(i << digit::$Digit::BYTE_SHIFT) - .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); - uninit.assume_init() - }; - let digit = $Digit::from_le_bytes(digit_bytes); - if i < N { - out.digits[i] = digit; - } else if digit != 0 { - return None; - }; - i += 1; - } - if len & (digit::$Digit::BYTES as usize - 1) == 0 { - Some(out) - } else { - let mut last_digit_bytes = [0; digit::$Digit::BYTES as usize]; - let addition = exact << digit::$Digit::BYTE_SHIFT; - let mut j = 0; - while j + addition < len { - last_digit_bytes[j] = slice[j + addition]; - j += 1; - } - let digit = $Digit::from_le_bytes(last_digit_bytes); - if i < N { - out.digits[i] = digit; - } else if digit != 0 { - return None; - }; - Some(out) - } - } - } + /// Creates an integer value from a slice of bytes in little endian. The value is wrapped in an `Option` as the bytes may represent an integer too large to be represented by the type. + /// + /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros at the end so that it's length equals `Self::BYTES`. + /// + /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless trailing zeros from the slice can be removed until the length of the slice equals `Self::BYTES`. + /// + /// # Examples + /// + /// ``` + /// // NB: This example requires the `nightly` feature to use the `from_le_bytes` method. + /// use bnum::types::U128; + /// + /// let value_from_array = U128::from(u128::from_le_bytes([0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0, 0])); // using the `from_le_bytes` method on the primitve `u128` here instead of on `U128` as `from_le_bytes` is currently only available in bnum on nightly + /// let value_from_slice = U128::from_le_slice(&[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56]).unwrap(); + /// let value_from_long_slice = U128::from_le_slice(&[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0, 0, 0, 0, 0, 0]).unwrap(); + /// + /// assert_eq!(value_from_array, value_from_slice); + /// assert_eq!(value_from_array, value_from_long_slice); + /// + /// let invalid_slice = &[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90]; + /// assert_eq!(U128::from_le_slice(invalid_slice), None); + /// ``` + #[must_use] + pub const fn from_le_slice(slice: &[u8]) -> Option { + let len = slice.len(); + let mut out = Self::ZERO; + let slice_ptr = slice.as_ptr(); + let mut i = 0; + let exact = len >> digit::$Digit::BYTE_SHIFT; + while i < exact { + let uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); + let ptr = uninit.as_ptr().cast_mut() as *mut u8; + let digit_bytes = unsafe { + slice_ptr + .add(i << digit::$Digit::BYTE_SHIFT) + .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); + uninit.assume_init() + }; + let digit = $Digit::from_le_bytes(digit_bytes); + if i < N { + out.digits[i] = digit; + } else if digit != 0 { + return None; + }; + i += 1; + } + if len & (digit::$Digit::BYTES as usize - 1) == 0 { + Some(out) + } else { + let mut last_digit_bytes = [0; digit::$Digit::BYTES as usize]; + let addition = exact << digit::$Digit::BYTE_SHIFT; + let mut j = 0; + while j + addition < len { + last_digit_bytes[j] = slice[j + addition]; + j += 1; + } + let digit = $Digit::from_le_bytes(last_digit_bytes); + if i < N { + out.digits[i] = digit; + } else if digit != 0 { + return None; + }; + Some(out) + } + } - #[cfg(feature = "nightly")] - #[doc = doc::endian::to_be_bytes!(U)] - #[doc = doc::requires_feature!("nightly")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_be_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { - let mut bytes = [0; N * digit::$Digit::BYTES as usize]; - let mut i = N; - while i > 0 { - let digit_bytes = self.digits[N - i].to_be_bytes(); - i -= 1; - let mut j = 0; - while j < digit::$Digit::BYTES as usize { - bytes[(i << digit::$Digit::BYTE_SHIFT) + j] = digit_bytes[j]; - j += 1; - } - } - bytes - } + #[cfg(feature = "nightly")] + #[doc = doc::endian::to_be_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_be_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { + let mut bytes = [0; N * digit::$Digit::BYTES as usize]; + let mut i = N; + while i > 0 { + let digit_bytes = self.digits[N - i].to_be_bytes(); + i -= 1; + let mut j = 0; + while j < digit::$Digit::BYTES as usize { + bytes[(i << digit::$Digit::BYTE_SHIFT) + j] = digit_bytes[j]; + j += 1; + } + } + bytes + } - #[cfg(feature = "nightly")] - #[doc = doc::endian::to_le_bytes!(U)] - #[doc = doc::requires_feature!("nightly")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_le_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { - // Strangely, this is slightly faster than direct transmutation by either `mem::transmute_copy` or `ptr::read`. - // Also, initialising the bytes with zeros is faster than using MaybeUninit. - // The Rust compiler is probably being very smart and optimizing this code. - // The same goes for `to_be_bytes`. - let mut bytes = [0; N * digit::$Digit::BYTES as usize]; - let mut i = 0; - while i < N { - let digit_bytes = self.digits[i].to_le_bytes(); - let mut j = 0; - while j < digit::$Digit::BYTES as usize { - bytes[(i << digit::$Digit::BYTE_SHIFT) + j] = digit_bytes[j]; - j += 1; - } - i += 1; - } - bytes - } + #[cfg(feature = "nightly")] + #[doc = doc::endian::to_le_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_le_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { + // Strangely, this is slightly faster than direct transmutation by either `mem::transmute_copy` or `ptr::read`. + // Also, initialising the bytes with zeros is faster than using MaybeUninit. + // The Rust compiler is probably being very smart and optimizing this code. + // The same goes for `to_be_bytes`. + let mut bytes = [0; N * digit::$Digit::BYTES as usize]; + let mut i = 0; + while i < N { + let digit_bytes = self.digits[i].to_le_bytes(); + let mut j = 0; + while j < digit::$Digit::BYTES as usize { + bytes[(i << digit::$Digit::BYTE_SHIFT) + j] = digit_bytes[j]; + j += 1; + } + i += 1; + } + bytes + } - #[cfg(feature = "nightly")] - #[doc = doc::endian::to_ne_bytes!(U)] - #[doc = doc::requires_feature!("nightly")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_ne_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { - #[cfg(target_endian = "big")] - return self.to_be_bytes(); - #[cfg(not(target_endian = "big"))] - self.to_le_bytes() - } + #[cfg(feature = "nightly")] + #[doc = doc::endian::to_ne_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_ne_bytes(self) -> [u8; N * digit::$Digit::BYTES as usize] { + #[cfg(target_endian = "big")] + return self.to_be_bytes(); + #[cfg(not(target_endian = "big"))] + self.to_le_bytes() + } - #[cfg(feature = "nightly")] - #[doc = doc::endian::from_be_bytes!(U)] - #[doc = doc::requires_feature!("nightly")] - #[must_use] - #[inline] - pub const fn from_be_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { - let mut out = Self::ZERO; - let arr_ptr = bytes.as_ptr(); - let mut i = 0; - while i < N { - let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); - let ptr = uninit.as_mut_ptr() as *mut u8; - let digit_bytes = unsafe { - arr_ptr - .add((N - 1 - i) << digit::$Digit::BYTE_SHIFT) - .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); - uninit.assume_init() - }; - out.digits[i] = $Digit::from_be_bytes(digit_bytes); - i += 1; - } - out - } + #[cfg(feature = "nightly")] + #[doc = doc::endian::from_be_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use] + #[inline] + pub const fn from_be_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { + let mut out = Self::ZERO; + let arr_ptr = bytes.as_ptr(); + let mut i = 0; + while i < N { + let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); + let ptr = uninit.as_mut_ptr() as *mut u8; + let digit_bytes = unsafe { + arr_ptr + .add((N - 1 - i) << digit::$Digit::BYTE_SHIFT) + .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); + uninit.assume_init() + }; + out.digits[i] = $Digit::from_be_bytes(digit_bytes); + i += 1; + } + out + } - #[cfg(feature = "nightly")] - #[doc = doc::endian::from_le_bytes!(U)] - #[doc = doc::requires_feature!("nightly")] - #[must_use] - #[inline] - pub const fn from_le_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { - let mut out = Self::ZERO; - let arr_ptr = bytes.as_ptr(); - let mut i = 0; - while i < N { - let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); - let ptr = uninit.as_mut_ptr() as *mut u8; - let digit_bytes = unsafe { - arr_ptr - .add(i << digit::$Digit::BYTE_SHIFT) - .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); - uninit.assume_init() - }; - out.digits[i] = $Digit::from_le_bytes(digit_bytes); - i += 1; - } - out - } + #[cfg(feature = "nightly")] + #[doc = doc::endian::from_le_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use] + #[inline] + pub const fn from_le_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { + let mut out = Self::ZERO; + let arr_ptr = bytes.as_ptr(); + let mut i = 0; + while i < N { + let mut uninit = MaybeUninit::<[u8; digit::$Digit::BYTES as usize]>::uninit(); + let ptr = uninit.as_mut_ptr() as *mut u8; + let digit_bytes = unsafe { + arr_ptr + .add(i << digit::$Digit::BYTE_SHIFT) + .copy_to_nonoverlapping(ptr, digit::$Digit::BYTES as usize); + uninit.assume_init() + }; + out.digits[i] = $Digit::from_le_bytes(digit_bytes); + i += 1; + } + out + } - #[cfg(feature = "nightly")] - #[doc = doc::endian::from_ne_bytes!(U)] - #[doc = doc::requires_feature!("nightly")] - #[must_use] - #[inline] - pub const fn from_ne_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { - #[cfg(target_endian = "big")] - return Self::from_be_bytes(bytes); + #[cfg(feature = "nightly")] + #[doc = doc::endian::from_ne_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use] + #[inline] + pub const fn from_ne_bytes(bytes: [u8; N * digit::$Digit::BYTES as usize]) -> Self { + #[cfg(target_endian = "big")] + return Self::from_be_bytes(bytes); - #[cfg(not(target_endian = "big"))] - Self::from_le_bytes(bytes) - } - } + #[cfg(not(target_endian = "big"))] + Self::from_le_bytes(bytes) + } + } - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::{test_bignum, types::utest}; + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::{test_bignum, types::utest}; - crate::int::endian::tests!($Digit; utest); - } - } - }; + crate::int::endian::tests!($Digit; utest); + } + } + }; } crate::macro_impl!(endian); diff --git a/src/buint/fmt.rs b/src/buint/fmt.rs index 403db86..5f4a163 100644 --- a/src/buint/fmt.rs +++ b/src/buint/fmt.rs @@ -4,110 +4,110 @@ use core::fmt::Write; use core::fmt::{Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, UpperExp, UpperHex}; macro_rules! fmt { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - macro_rules! fmt_method { - ($format: expr, $format_pad: expr, $pad: expr, $prefix: expr) => { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - let mut format_string = String::new(); - for digit in self.digits.iter().rev() { - if format_string.is_empty() { - if digit != &0 { - write!(format_string, $format, digit)?; - } - } else { - write!(format_string, $format_pad, digit, $pad)?; - } - } - f.pad_integral( - true, - $prefix, - if format_string.is_empty() { - "0" - } else { - &format_string - }, - ) - } - }; - } + ($BUint: ident, $BInt: ident, $Digit: ident) => { + macro_rules! fmt_method { + ($format: expr, $format_pad: expr, $pad: expr, $prefix: expr) => { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + let mut format_string = String::new(); + for digit in self.digits.iter().rev() { + if format_string.is_empty() { + if digit != &0 { + write!(format_string, $format, digit)?; + } + } else { + write!(format_string, $format_pad, digit, $pad)?; + } + } + f.pad_integral( + true, + $prefix, + if format_string.is_empty() { + "0" + } else { + &format_string + }, + ) + } + }; + } - impl Binary for $BUint { - fmt_method!("{:b}", "{:01$b}", digit::$Digit::BITS as usize, "0b"); - } + impl Binary for $BUint { + fmt_method!("{:b}", "{:01$b}", digit::$Digit::BITS as usize, "0b"); + } - impl Debug for $BUint { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - Display::fmt(&self, f) - } - } + impl Debug for $BUint { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + Display::fmt(&self, f) + } + } - impl Display for $BUint { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - write!(f, "{}", self.to_str_radix(10)) - } - } + impl Display for $BUint { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + write!(f, "{}", self.to_str_radix(10)) + } + } - macro_rules! exp_fmt { - ($e: expr) => { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - let decimal_str = format!("{}", self); - if decimal_str == "0" { - return write!(f, "{}{}0", 0, $e); - } - let exp = decimal_str.len() - 1; - let decimal_str = decimal_str.trim_end_matches('0'); - if decimal_str.len() == 1 { - write!(f, "{}{}{}", &decimal_str[0..1], $e, exp) - } else { - write!( - f, - "{}.{}{}{}", - &decimal_str[0..1], - &decimal_str[1..], - $e, - exp - ) - } - } - }; - } + macro_rules! exp_fmt { + ($e: expr) => { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + let decimal_str = format!("{}", self); + if decimal_str == "0" { + return write!(f, "{}{}0", 0, $e); + } + let exp = decimal_str.len() - 1; + let decimal_str = decimal_str.trim_end_matches('0'); + if decimal_str.len() == 1 { + write!(f, "{}{}{}", &decimal_str[0..1], $e, exp) + } else { + write!( + f, + "{}.{}{}{}", + &decimal_str[0..1], + &decimal_str[1..], + $e, + exp + ) + } + } + }; + } - impl LowerExp for $BUint { - exp_fmt!("e"); - } + impl LowerExp for $BUint { + exp_fmt!("e"); + } - impl LowerHex for $BUint { - fmt_method!("{:x}", "{:01$x}", digit::$Digit::HEX_PADDING, "0x"); - } + impl LowerHex for $BUint { + fmt_method!("{:x}", "{:01$x}", digit::$Digit::HEX_PADDING, "0x"); + } - impl Octal for $BUint { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - let string = self.to_str_radix(8); - f.pad_integral(true, "0o", &string) - } - } + impl Octal for $BUint { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + let string = self.to_str_radix(8); + f.pad_integral(true, "0o", &string) + } + } - impl UpperExp for $BUint { - exp_fmt!("E"); - } + impl UpperExp for $BUint { + exp_fmt!("E"); + } - impl UpperHex for $BUint { - fmt_method!("{:X}", "{:01$X}", digit::$Digit::HEX_PADDING, "0x"); - } + impl UpperHex for $BUint { + fmt_method!("{:X}", "{:01$X}", digit::$Digit::HEX_PADDING, "0x"); + } - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - crate::int::fmt::tests!(utest); - } - } - }; + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + crate::int::fmt::tests!(utest); + } + } + }; } crate::macro_impl!(fmt); diff --git a/src/buint/mod.rs b/src/buint/mod.rs index 12ec6d8..91cd21e 100644 --- a/src/buint/mod.rs +++ b/src/buint/mod.rs @@ -16,666 +16,660 @@ use core::default::Default; use core::iter::{Iterator, Product, Sum}; +#[cfg(feature = "arbitrary")] +use arbitrary::Arbitrary; + macro_rules! mod_impl { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - /// Unsigned integer type composed of - #[doc = concat!("`", stringify!($Digit), "`")] - /// digits, of arbitrary fixed size which must be known at compile time. - /// - /// Digits are stored in little endian (least significant digit first). This integer type aims to exactly replicate the behaviours of Rust's built-in unsigned integer types: `u8`, `u16`, `u32`, `u64`, `u128` and `usize`. The const generic parameter `N` is the number of - #[doc = concat!("`", stringify!($Digit), "`")] - /// digits that are stored. - /// - #[doc = doc::arithmetic_doc!($BUint)] - - // Clippy: we can allow derivation of `Hash` and manual implementation of `PartialEq` as the derived `PartialEq` would be the same except we make our implementation const. - #[allow(clippy::derive_hash_xor_eq)] - #[derive(Clone, Copy, Hash)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] - pub struct $BUint { - #[cfg_attr(feature = "serde", serde(with = "BigArray"))] - pub(crate) digits: [$Digit; N], - } - - impl $BUint { - #[doc = doc::count_ones!(U 1024)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn count_ones(self) -> ExpType { - let mut ones = 0; - let mut i = 0; - while i < N { - ones += self.digits[i].count_ones() as ExpType; - i += 1; - } - ones - } - - #[doc = doc::count_zeros!(U 1024)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn count_zeros(self) -> ExpType { - let mut zeros = 0; - let mut i = 0; - while i < N { - zeros += self.digits[i].count_zeros() as ExpType; - i += 1; - } - zeros - } - - #[doc = doc::leading_zeros!(U 1024)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn leading_zeros(self) -> ExpType { - let mut zeros = 0; - let mut i = N; - while i > 0 { - i -= 1; - let digit = self.digits[i]; - zeros += digit.leading_zeros() as ExpType; - if digit != $Digit::MIN { - break; - } - } - zeros - } - - #[doc = doc::trailing_zeros!(U 1024)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn trailing_zeros(self) -> ExpType { - let mut zeros = 0; - let mut i = 0; - while i < N { - let digit = self.digits[i]; - zeros += digit.trailing_zeros() as ExpType; - if digit != $Digit::MIN { - break; - } - i += 1; - } - zeros - } - - #[doc = doc::leading_ones!(U 1024, MAX)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn leading_ones(self) -> ExpType { - let mut ones = 0; - let mut i = N; - while i > 0 { - i -= 1; - let digit = self.digits[i]; - ones += digit.leading_ones() as ExpType; - if digit != $Digit::MAX { - break; - } - } - ones - } - - #[doc = doc::trailing_ones!(U 1024)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn trailing_ones(self) -> ExpType { - let mut ones = 0; - let mut i = 0; - while i < N { - let digit = self.digits[i]; - ones += digit.trailing_ones() as ExpType; - if digit != $Digit::MAX { - break; - } - i += 1; - } - ones - } - - crate::nightly::const_fns! { - #[inline] - const unsafe fn rotate_digits_left(self, n: usize) -> Self { - let mut uninit = MaybeUninit::<[$Digit; N]>::uninit(); - let digits_ptr = self.digits.as_ptr(); - let uninit_ptr = uninit.as_mut_ptr() as *mut $Digit; - - digits_ptr.copy_to_nonoverlapping(uninit_ptr.add(n), N - n); - digits_ptr.add(N - n).copy_to_nonoverlapping(uninit_ptr, n); - Self::from_digits(uninit.assume_init()) - } - - #[inline] - const unsafe fn unchecked_rotate_left(self, rhs: ExpType) -> Self { - let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize; - let bit_shift = rhs & digit::$Digit::BITS_MINUS_1; - - let mut out = self.rotate_digits_left(digit_shift); - - if bit_shift != 0 { - let carry_shift = digit::$Digit::BITS - bit_shift; - let mut carry = 0; - - let mut i = 0; - while i < N { - let current_digit = out.digits[i]; - out.digits[i] = (current_digit << bit_shift) | carry; - carry = current_digit >> carry_shift; - i += 1; - } - out.digits[0] |= carry; - } - - out - } - } - - const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType; - - crate::nightly::const_fns! { - #[doc = doc::rotate_left!(U 256, "u")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn rotate_left(self, n: ExpType) -> Self { - unsafe { - self.unchecked_rotate_left(n & Self::BITS_MINUS_1) - } - } - - #[doc = doc::rotate_right!(U 256, "u")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn rotate_right(self, n: ExpType) -> Self { - let n = n & Self::BITS_MINUS_1; - unsafe { - self.unchecked_rotate_left(Self::BITS as ExpType - n) - } - } - } - - const N_MINUS_1: usize = N - 1; - - #[doc = doc::swap_bytes!(U 256, "u")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn swap_bytes(self) -> Self { - let mut uint = Self::ZERO; - let mut i = 0; - while i < N { - uint.digits[i] = self.digits[Self::N_MINUS_1 - i].swap_bytes(); - i += 1; - } - uint - } - - #[doc = doc::reverse_bits!(U 256, "u")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn reverse_bits(self) -> Self { - let mut uint = Self::ZERO; - let mut i = 0; - while i < N { - uint.digits[i] = self.digits[Self::N_MINUS_1 - i].reverse_bits(); - i += 1; - } - uint - } - - #[doc = doc::pow!(U 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn pow(self, exp: ExpType) -> Self { - #[cfg(debug_assertions)] - return option_expect!( - self.checked_pow(exp), - errors::err_msg!("attempt to calculate power with overflow") - ); - #[cfg(not(debug_assertions))] - self.wrapping_pow(exp) - } - - crate::nightly::const_fns! { - #[doc = doc::div_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn div_euclid(self, rhs: Self) -> Self { - self.wrapping_div_euclid(rhs) - } - - - #[doc = doc::rem_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn rem_euclid(self, rhs: Self) -> Self { - self.wrapping_rem_euclid(rhs) - } - } - - #[doc = doc::doc_comment! { - U 256, - "Returns `true` if and only if `self == 2^k` for some integer `k`.", - - "let n = " stringify!(U256) "::from(1u16 << 14);\n" - "assert!(n.is_power_of_two());\n" - "let m = " stringify!(U256) "::from(100u8);\n" - "assert!(!m.is_power_of_two());" - }] - #[must_use] - #[inline] - pub const fn is_power_of_two(self) -> bool { - let mut i = 0; - let mut ones = 0; - while i < N { - ones += (&self.digits)[i].count_ones(); - if ones > 1 { - return false; - } - i += 1; - } - ones == 1 - } - - #[doc = doc::next_power_of_two!(U 256, "0", "ZERO")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn next_power_of_two(self) -> Self { - #[cfg(debug_assertions)] - return option_expect!( - self.checked_next_power_of_two(), - errors::err_msg!("attempt to calculate next power of two with overflow") - ); - #[cfg(not(debug_assertions))] - self.wrapping_next_power_of_two() - } - - #[doc = doc::ilog2!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn ilog2(self) -> ExpType { - #[cfg(debug_assertions)] - return option_expect!( - self.checked_ilog2(), - errors::err_msg!("attempt to calculate ilog2 of zero") - ); - #[cfg(not(debug_assertions))] - match self.checked_ilog2() { - Some(n) => n, - None => 0, - } - } - - crate::nightly::const_fns! { - #[doc = doc::ilog10!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn ilog10(self) -> ExpType { - #[cfg(debug_assertions)] - return option_expect!(self.checked_ilog10(), errors::err_msg!("attempt to calculate ilog10 of zero")); - #[cfg(not(debug_assertions))] - match self.checked_ilog10() { - Some(n) => n, - None => 0, - } - } - - #[doc = doc::ilog!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn ilog(self, base: Self) -> ExpType { - #[cfg(debug_assertions)] - return option_expect!(self.checked_ilog(base), errors::err_msg!("attempt to calculate ilog of zero or ilog with base < 2")); - #[cfg(not(debug_assertions))] - match self.checked_ilog(base) { - Some(n) => n, - None => 0, - } - } - } - - #[doc = doc::abs_diff!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn abs_diff(self, other: Self) -> Self { - if self.lt(other) { - other.wrapping_sub(self) - } else { - self.wrapping_sub(other) - } - } - - crate::nightly::const_fns! { - #[doc = doc::next_multiple_of!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn next_multiple_of(self, rhs: Self) -> Self { - let rem = self.wrapping_rem(rhs); - if rem.is_zero() { - self - } else { - self.add(rhs.sub(rem)) - } - } - - #[doc = doc::div_floor!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn div_floor(self, rhs: Self) -> Self { - self.wrapping_div(rhs) - } - - #[doc = doc::div_ceil!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn div_ceil(self, rhs: Self) -> Self { - let (div, rem) = self.div_rem(rhs); - if rem.is_zero() { - div - } else { - div.add(Self::ONE) - } - } - } - } - - impl $BUint { - crate::nightly::const_fn! { - #[inline] - pub(crate) const unsafe fn unchecked_shl_internal(u: $BUint, rhs: ExpType) -> $BUint { - let mut out = $BUint::ZERO; - let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize; - let bit_shift = rhs & digit::$Digit::BITS_MINUS_1; - - let num_copies = N - digit_shift; - - u.digits.as_ptr().copy_to_nonoverlapping(out.digits.as_mut_ptr().add(digit_shift), num_copies); - - if bit_shift != 0 { - let carry_shift = digit::$Digit::BITS - bit_shift; - let mut carry = 0; - - let mut i = digit_shift; - while i < N { - let current_digit = out.digits[i]; - out.digits[i] = (current_digit << bit_shift) | carry; - carry = current_digit >> carry_shift; - i += 1; - } - } - - out - } - } - - crate::nightly::const_fn! { - #[inline] - pub(crate) const unsafe fn unchecked_shr_pad_internal(u: $BUint, rhs: ExpType) -> $BUint { - let mut out = $BUint::from_digits([PAD; N]); - let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize; - let bit_shift = rhs & digit::$Digit::BITS_MINUS_1; - - let num_copies = N - digit_shift; - - u.digits.as_ptr().add(digit_shift).copy_to_nonoverlapping(out.digits.as_mut_ptr(), num_copies); - - if bit_shift != 0 { - let carry_shift = digit::$Digit::BITS - bit_shift; - let mut carry = 0; - - let mut i = num_copies; - while i > 0 { - i -= 1; - let current_digit = out.digits[i]; - out.digits[i] = (current_digit >> bit_shift) | carry; - carry = current_digit << carry_shift; - } - - if PAD == $Digit::MAX { - out.digits[num_copies - 1] |= $Digit::MAX << carry_shift; - } - } - - out - } - } - - crate::nightly::const_fn! { - pub(crate) const unsafe fn unchecked_shr_internal(u: $BUint, rhs: ExpType) -> $BUint { - Self::unchecked_shr_pad_internal::<{$Digit::MIN}>(u, rhs) - } - } - - #[doc = doc::bits!(U 256)] - #[must_use] - #[inline] - pub const fn bits(&self) -> ExpType { - Self::BITS as ExpType - self.leading_zeros() - } - - #[doc = doc::bit!(U 256)] - #[must_use] - #[inline] - pub const fn bit(&self, index: ExpType) -> bool { - let digit = self.digits[index as usize >> digit::$Digit::BIT_SHIFT]; - digit & (1 << (index & digit::$Digit::BITS_MINUS_1)) != 0 - } - - /// Returns an integer whose value is `2^power`. This is faster than using a shift left on `Self::ONE`. - /// - /// # Panics - /// - /// This function will panic if `power` is greater than or equal to `Self::BITS`. - /// - /// # Examples - /// - /// ``` - /// use bnum::types::U256; - /// - /// let power = 11; - /// assert_eq!(U256::power_of_two(11), (1u128 << 11).into()); - /// ``` - #[must_use] - #[inline] - pub const fn power_of_two(power: ExpType) -> Self { - let mut out = Self::ZERO; - out.digits[power as usize >> digit::$Digit::BIT_SHIFT] = 1 << (power & (digit::$Digit::BITS - 1)); - out - } - - /// Returns the digits stored in `self` as an array. Digits are little endian (least significant digit first). - #[must_use] - #[inline(always)] - pub const fn digits(&self) -> &[$Digit; N] { - &self.digits - } - - /// Creates a new unsigned integer from the given array of digits. Digits are stored as little endian (least significant digit first). - #[must_use] - #[inline(always)] - pub const fn from_digits(digits: [$Digit; N]) -> Self { - Self { digits } - } - - /// Creates a new unsigned integer from the given digit. The given digit is stored as the least significant digit. - #[must_use] - #[inline(always)] - pub const fn from_digit(digit: $Digit) -> Self { - let mut out = Self::ZERO; - out.digits[0] = digit; - out - } - - #[doc = doc::is_zero!(U 256)] - #[must_use] - #[inline] - pub const fn is_zero(&self) -> bool { - let mut i = 0; - while i < N { - if (&self.digits)[i] != 0 { - return false; - } - i += 1; - } - true - } - - #[doc = doc::is_one!(U 256)] - #[must_use] - #[inline] - pub const fn is_one(&self) -> bool { - if N == 0 || self.digits[0] != 1 { - return false; - } - let mut i = 1; - while i < N { - if (&self.digits)[i] != 0 { - return false; - } - i += 1; - } - true - } - - #[inline] - pub(crate) const fn last_digit_index(&self) -> usize { - let mut index = 0; - let mut i = 1; - while i < N { - if (&self.digits)[i] != 0 { - index = i; - } - i += 1; - } - index - } - - #[inline] - pub(crate) const fn to_exp_type(self) -> Option { - let last_index = self.last_digit_index(); - if self.digits[last_index] == 0 { - return Some(0); - } - if last_index >= ExpType::BITS as usize >> digit::$Digit::BIT_SHIFT { - return None; - } - let mut out = 0; - let mut i = 0; - while i <= last_index { - out |= (self.digits[i] as ExpType) << (i << digit::$Digit::BIT_SHIFT); - i += 1; - } - Some(out) - } - - #[allow(unused)] - #[inline] - fn square(self) -> Self { - // TODO: optimise this method, this will make exponentiation by squaring faster - self * self - } - } - - impl Default for $BUint { - #[doc = doc::default!()] - #[inline] - fn default() -> Self { - Self::ZERO - } - } - - impl Product for $BUint { - #[inline] - fn product>(iter: I) -> Self { - iter.fold(Self::ONE, |a, b| a * b) - } - } - - impl<'a, const N: usize> Product<&'a Self> for $BUint { - #[inline] - fn product>(iter: I) -> Self { - iter.fold(Self::ONE, |a, b| a * b) - } - } - - impl Sum for $BUint { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::ZERO, |a, b| a + b) - } - } - - impl<'a, const N: usize> Sum<&'a Self> for $BUint { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::ZERO, |a, b| a + b) - } - } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::{debug_skip, test_bignum, types::utest}; - use crate::test::types::big_types::$Digit::*; - - crate::int::tests!(utest); - - test_bignum! { - function: ::next_power_of_two(a: utest), - skip: debug_skip!(a.checked_next_power_of_two().is_none()) - } - - test_bignum! { - function: ::is_power_of_two(a: utest) - } - - #[test] - fn bit() { - let u = UTEST::from(0b001010100101010101u64); - assert!(u.bit(0)); - assert!(!u.bit(1)); - assert!(!u.bit(17)); - assert!(!u.bit(16)); - assert!(u.bit(15)); - } - - #[test] - fn is_zero() { - assert!(UTEST::MIN.is_zero()); - assert!(!UTEST::MAX.is_zero()); - assert!(!UTEST::ONE.is_zero()); - } - - #[test] - fn is_one() { - assert!(UTEST::ONE.is_one()); - assert!(!UTEST::MAX.is_one()); - assert!(!UTEST::ZERO.is_one()); - } - - #[test] - fn bits() { - let u = UTEST::from(0b1001010100101010101u128); - assert_eq!(u.bits(), 19); - - let u = UTEST::power_of_two(34); - assert_eq!(u.bits(), 35); - } - - #[test] - fn default() { - assert_eq!(UTEST::default(), utest::default().into()); - } - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + /// Unsigned integer type composed of + #[doc = concat!("`", stringify!($Digit), "`")] + /// digits, of arbitrary fixed size which must be known at compile time. + /// + /// Digits are stored in little endian (least significant digit first). This integer type aims to exactly replicate the behaviours of Rust's built-in unsigned integer types: `u8`, `u16`, `u32`, `u64`, `u128` and `usize`. The const generic parameter `N` is the number of + #[doc = concat!("`", stringify!($Digit), "`")] + /// digits that are stored. + /// + #[doc = doc::arithmetic_doc!($BUint)] + + // Clippy: we can allow derivation of `Hash` and manual implementation of `PartialEq` as the derived `PartialEq` would be the same except we make our implementation const. + #[allow(clippy::derive_hash_xor_eq)] + #[derive(Clone, Copy, Hash)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] + pub struct $BUint { + #[cfg_attr(feature = "serde", serde(with = "BigArray"))] + pub(crate) digits: [$Digit; N], + } + + impl $BUint { + #[doc = doc::count_ones!(U 1024)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn count_ones(self) -> ExpType { + let mut ones = 0; + let mut i = 0; + while i < N { + ones += self.digits[i].count_ones() as ExpType; + i += 1; + } + ones + } + + #[doc = doc::count_zeros!(U 1024)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn count_zeros(self) -> ExpType { + let mut zeros = 0; + let mut i = 0; + while i < N { + zeros += self.digits[i].count_zeros() as ExpType; + i += 1; + } + zeros + } + + #[doc = doc::leading_zeros!(U 1024)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn leading_zeros(self) -> ExpType { + let mut zeros = 0; + let mut i = N; + while i > 0 { + i -= 1; + let digit = self.digits[i]; + zeros += digit.leading_zeros() as ExpType; + if digit != $Digit::MIN { + break; + } + } + zeros + } + + #[doc = doc::trailing_zeros!(U 1024)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn trailing_zeros(self) -> ExpType { + let mut zeros = 0; + let mut i = 0; + while i < N { + let digit = self.digits[i]; + zeros += digit.trailing_zeros() as ExpType; + if digit != $Digit::MIN { + break; + } + i += 1; + } + zeros + } + + #[doc = doc::leading_ones!(U 1024, MAX)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn leading_ones(self) -> ExpType { + let mut ones = 0; + let mut i = N; + while i > 0 { + i -= 1; + let digit = self.digits[i]; + ones += digit.leading_ones() as ExpType; + if digit != $Digit::MAX { + break; + } + } + ones + } + + #[doc = doc::trailing_ones!(U 1024)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn trailing_ones(self) -> ExpType { + let mut ones = 0; + let mut i = 0; + while i < N { + let digit = self.digits[i]; + ones += digit.trailing_ones() as ExpType; + if digit != $Digit::MAX { + break; + } + i += 1; + } + ones + } + + #[inline] + const unsafe fn rotate_digits_left(self, n: usize) -> Self { + let uninit = MaybeUninit::<[$Digit; N]>::uninit(); + let digits_ptr = self.digits.as_ptr(); + let uninit_ptr = uninit.as_ptr().cast_mut() as *mut $Digit; // TODO: can change to as_mut_ptr() when const_mut_refs is stabilised + + digits_ptr.copy_to_nonoverlapping(uninit_ptr.add(n), N - n); + digits_ptr.add(N - n).copy_to_nonoverlapping(uninit_ptr, n); + Self::from_digits(uninit.assume_init()) + } + + #[inline] + const unsafe fn unchecked_rotate_left(self, rhs: ExpType) -> Self { + let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize; + let bit_shift = rhs & digit::$Digit::BITS_MINUS_1; + + let mut out = self.rotate_digits_left(digit_shift); + + if bit_shift != 0 { + let carry_shift = digit::$Digit::BITS - bit_shift; + let mut carry = 0; + + let mut i = 0; + while i < N { + let current_digit = out.digits[i]; + out.digits[i] = (current_digit << bit_shift) | carry; + carry = current_digit >> carry_shift; + i += 1; + } + out.digits[0] |= carry; + } + + out + } + + const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType; + + #[doc = doc::rotate_left!(U 256, "u")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn rotate_left(self, n: ExpType) -> Self { + unsafe { + self.unchecked_rotate_left(n & Self::BITS_MINUS_1) + } + } + + #[doc = doc::rotate_right!(U 256, "u")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn rotate_right(self, n: ExpType) -> Self { + let n = n & Self::BITS_MINUS_1; + unsafe { + self.unchecked_rotate_left(Self::BITS as ExpType - n) + } + } + + const N_MINUS_1: usize = N - 1; + + #[doc = doc::swap_bytes!(U 256, "u")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn swap_bytes(self) -> Self { + let mut uint = Self::ZERO; + let mut i = 0; + while i < N { + uint.digits[i] = self.digits[Self::N_MINUS_1 - i].swap_bytes(); + i += 1; + } + uint + } + + #[doc = doc::reverse_bits!(U 256, "u")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn reverse_bits(self) -> Self { + let mut uint = Self::ZERO; + let mut i = 0; + while i < N { + uint.digits[i] = self.digits[Self::N_MINUS_1 - i].reverse_bits(); + i += 1; + } + uint + } + + #[doc = doc::pow!(U 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn pow(self, exp: ExpType) -> Self { + #[cfg(debug_assertions)] + return option_expect!( + self.checked_pow(exp), + errors::err_msg!("attempt to calculate power with overflow") + ); + #[cfg(not(debug_assertions))] + self.wrapping_pow(exp) + } + + crate::nightly::const_fns! { + #[doc = doc::div_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn div_euclid(self, rhs: Self) -> Self { + self.wrapping_div_euclid(rhs) + } + + + #[doc = doc::rem_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn rem_euclid(self, rhs: Self) -> Self { + self.wrapping_rem_euclid(rhs) + } + } + + #[doc = doc::doc_comment! { + U 256, + "Returns `true` if and only if `self == 2^k` for some integer `k`.", + + "let n = " stringify!(U256) "::from(1u16 << 14);\n" + "assert!(n.is_power_of_two());\n" + "let m = " stringify!(U256) "::from(100u8);\n" + "assert!(!m.is_power_of_two());" + }] + #[must_use] + #[inline] + pub const fn is_power_of_two(self) -> bool { + let mut i = 0; + let mut ones = 0; + while i < N { + ones += (&self.digits)[i].count_ones(); + if ones > 1 { + return false; + } + i += 1; + } + ones == 1 + } + + #[doc = doc::next_power_of_two!(U 256, "0", "ZERO")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn next_power_of_two(self) -> Self { + #[cfg(debug_assertions)] + return option_expect!( + self.checked_next_power_of_two(), + errors::err_msg!("attempt to calculate next power of two with overflow") + ); + #[cfg(not(debug_assertions))] + self.wrapping_next_power_of_two() + } + + #[doc = doc::ilog2!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn ilog2(self) -> ExpType { + #[cfg(debug_assertions)] + return option_expect!( + self.checked_ilog2(), + errors::err_msg!("attempt to calculate ilog2 of zero") + ); + #[cfg(not(debug_assertions))] + match self.checked_ilog2() { + Some(n) => n, + None => 0, + } + } + + crate::nightly::const_fns! { + #[doc = doc::ilog10!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn ilog10(self) -> ExpType { + #[cfg(debug_assertions)] + return option_expect!(self.checked_ilog10(), errors::err_msg!("attempt to calculate ilog10 of zero")); + #[cfg(not(debug_assertions))] + match self.checked_ilog10() { + Some(n) => n, + None => 0, + } + } + + #[doc = doc::ilog!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn ilog(self, base: Self) -> ExpType { + #[cfg(debug_assertions)] + return option_expect!(self.checked_ilog(base), errors::err_msg!("attempt to calculate ilog of zero or ilog with base < 2")); + #[cfg(not(debug_assertions))] + match self.checked_ilog(base) { + Some(n) => n, + None => 0, + } + } + } + + #[doc = doc::abs_diff!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn abs_diff(self, other: Self) -> Self { + if self.lt(other) { + other.wrapping_sub(self) + } else { + self.wrapping_sub(other) + } + } + + crate::nightly::const_fns! { + #[doc = doc::next_multiple_of!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn next_multiple_of(self, rhs: Self) -> Self { + let rem = self.wrapping_rem(rhs); + if rem.is_zero() { + self + } else { + self.add(rhs.sub(rem)) + } + } + + #[doc = doc::div_floor!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn div_floor(self, rhs: Self) -> Self { + self.wrapping_div(rhs) + } + + #[doc = doc::div_ceil!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn div_ceil(self, rhs: Self) -> Self { + let (div, rem) = self.div_rem(rhs); + if rem.is_zero() { + div + } else { + div.add(Self::ONE) + } + } + } + } + + impl $BUint { + #[inline] + pub(crate) const unsafe fn unchecked_shl_internal(u: $BUint, rhs: ExpType) -> $BUint { + let mut out = $BUint::ZERO; + let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize; + let bit_shift = rhs & digit::$Digit::BITS_MINUS_1; + + let num_copies = N - digit_shift; + + u.digits.as_ptr().copy_to_nonoverlapping(out.digits.as_ptr().cast_mut().add(digit_shift), num_copies); // TODO: can change to out.digits.as_mut_ptr() when const_mut_refs is stabilised + + if bit_shift != 0 { + let carry_shift = digit::$Digit::BITS - bit_shift; + let mut carry = 0; + + let mut i = digit_shift; + while i < N { + let current_digit = out.digits[i]; + out.digits[i] = (current_digit << bit_shift) | carry; + carry = current_digit >> carry_shift; + i += 1; + } + } + + out + } + + #[inline] + pub(crate) const unsafe fn unchecked_shr_pad_internal(u: $BUint, rhs: ExpType) -> $BUint { + let mut out = $BUint::from_digits([PAD; N]); + let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize; + let bit_shift = rhs & digit::$Digit::BITS_MINUS_1; + + let num_copies = N - digit_shift; + + u.digits.as_ptr().add(digit_shift).copy_to_nonoverlapping(out.digits.as_ptr().cast_mut(), num_copies); // TODO: can change to out.digits.as_mut_ptr() when const_mut_refs is stabilised + + if bit_shift != 0 { + let carry_shift = digit::$Digit::BITS - bit_shift; + let mut carry = 0; + + let mut i = num_copies; + while i > 0 { + i -= 1; + let current_digit = out.digits[i]; + out.digits[i] = (current_digit >> bit_shift) | carry; + carry = current_digit << carry_shift; + } + + if PAD == $Digit::MAX { + out.digits[num_copies - 1] |= $Digit::MAX << carry_shift; + } + } + + out + } + + pub(crate) const unsafe fn unchecked_shr_internal(u: $BUint, rhs: ExpType) -> $BUint { + Self::unchecked_shr_pad_internal::<{$Digit::MIN}>(u, rhs) + } + + #[doc = doc::bits!(U 256)] + #[must_use] + #[inline] + pub const fn bits(&self) -> ExpType { + Self::BITS as ExpType - self.leading_zeros() + } + + #[doc = doc::bit!(U 256)] + #[must_use] + #[inline] + pub const fn bit(&self, index: ExpType) -> bool { + let digit = self.digits[index as usize >> digit::$Digit::BIT_SHIFT]; + digit & (1 << (index & digit::$Digit::BITS_MINUS_1)) != 0 + } + + /// Returns an integer whose value is `2^power`. This is faster than using a shift left on `Self::ONE`. + /// + /// # Panics + /// + /// This function will panic if `power` is greater than or equal to `Self::BITS`. + /// + /// # Examples + /// + /// ``` + /// use bnum::types::U256; + /// + /// let power = 11; + /// assert_eq!(U256::power_of_two(11), (1u128 << 11).into()); + /// ``` + #[must_use] + #[inline] + pub const fn power_of_two(power: ExpType) -> Self { + let mut out = Self::ZERO; + out.digits[power as usize >> digit::$Digit::BIT_SHIFT] = 1 << (power & (digit::$Digit::BITS - 1)); + out + } + + /// Returns the digits stored in `self` as an array. Digits are little endian (least significant digit first). + #[must_use] + #[inline(always)] + pub const fn digits(&self) -> &[$Digit; N] { + &self.digits + } + + /// Creates a new unsigned integer from the given array of digits. Digits are stored as little endian (least significant digit first). + #[must_use] + #[inline(always)] + pub const fn from_digits(digits: [$Digit; N]) -> Self { + Self { digits } + } + + /// Creates a new unsigned integer from the given digit. The given digit is stored as the least significant digit. + #[must_use] + #[inline(always)] + pub const fn from_digit(digit: $Digit) -> Self { + let mut out = Self::ZERO; + out.digits[0] = digit; + out + } + + #[doc = doc::is_zero!(U 256)] + #[must_use] + #[inline] + pub const fn is_zero(&self) -> bool { + let mut i = 0; + while i < N { + if (&self.digits)[i] != 0 { + return false; + } + i += 1; + } + true + } + + #[doc = doc::is_one!(U 256)] + #[must_use] + #[inline] + pub const fn is_one(&self) -> bool { + if N == 0 || self.digits[0] != 1 { + return false; + } + let mut i = 1; + while i < N { + if (&self.digits)[i] != 0 { + return false; + } + i += 1; + } + true + } + + #[inline] + pub(crate) const fn last_digit_index(&self) -> usize { + let mut index = 0; + let mut i = 1; + while i < N { + if (&self.digits)[i] != 0 { + index = i; + } + i += 1; + } + index + } + + #[inline] + pub(crate) const fn to_exp_type(self) -> Option { + let last_index = self.last_digit_index(); + if self.digits[last_index] == 0 { + return Some(0); + } + if last_index >= ExpType::BITS as usize >> digit::$Digit::BIT_SHIFT { + return None; + } + let mut out = 0; + let mut i = 0; + while i <= last_index { + out |= (self.digits[i] as ExpType) << (i << digit::$Digit::BIT_SHIFT); + i += 1; + } + Some(out) + } + + #[allow(unused)] + #[inline] + fn square(self) -> Self { + // TODO: optimise this method, this will make exponentiation by squaring faster + self * self + } + } + + impl Default for $BUint { + #[doc = doc::default!()] + #[inline] + fn default() -> Self { + Self::ZERO + } + } + + impl Product for $BUint { + #[inline] + fn product>(iter: I) -> Self { + iter.fold(Self::ONE, |a, b| a * b) + } + } + + impl<'a, const N: usize> Product<&'a Self> for $BUint { + #[inline] + fn product>(iter: I) -> Self { + iter.fold(Self::ONE, |a, b| a * b) + } + } + + impl Sum for $BUint { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |a, b| a + b) + } + } + + impl<'a, const N: usize> Sum<&'a Self> for $BUint { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |a, b| a + b) + } + } + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::{debug_skip, test_bignum, types::utest}; + use crate::test::types::big_types::$Digit::*; + + crate::int::tests!(utest); + + test_bignum! { + function: ::next_power_of_two(a: utest), + skip: debug_skip!(a.checked_next_power_of_two().is_none()) + } + + test_bignum! { + function: ::is_power_of_two(a: utest) + } + + #[test] + fn bit() { + let u = UTEST::from(0b001010100101010101u64); + assert!(u.bit(0)); + assert!(!u.bit(1)); + assert!(!u.bit(17)); + assert!(!u.bit(16)); + assert!(u.bit(15)); + } + + #[test] + fn is_zero() { + assert!(UTEST::MIN.is_zero()); + assert!(!UTEST::MAX.is_zero()); + assert!(!UTEST::ONE.is_zero()); + } + + #[test] + fn is_one() { + assert!(UTEST::ONE.is_one()); + assert!(!UTEST::MAX.is_one()); + assert!(!UTEST::ZERO.is_one()); + } + + #[test] + fn bits() { + let u = UTEST::from(0b1001010100101010101u128); + assert_eq!(u.bits(), 19); + + let u = UTEST::power_of_two(34); + assert_eq!(u.bits(), 35); + } + + #[test] + fn default() { + assert_eq!(UTEST::default(), utest::default().into()); + } + } + } + }; } crate::main_impl!(mod_impl); -mod consts; mod bigint_helpers; mod cast; mod checked; mod cmp; mod const_trait_fillers; +mod consts; mod convert; mod endian; mod fmt; @@ -686,4 +680,4 @@ mod overflowing; mod radix; mod saturating; mod unchecked; -mod wrapping; \ No newline at end of file +mod wrapping; diff --git a/src/buint/numtraits.rs b/src/buint/numtraits.rs index f5c30b9..9a96d94 100644 --- a/src/buint/numtraits.rs +++ b/src/buint/numtraits.rs @@ -1,45 +1,45 @@ macro_rules! to_int { - { $Digit: ident; $($name: ident -> $int: ty), * } => { - $( - #[inline] - fn $name(&self) -> Option<$int> { - let mut out = 0; - let mut i = 0; - if $Digit::BITS > <$int>::BITS { - let small = self.digits[i] as $int; - let trunc = small as $Digit; - if self.digits[i] != trunc { - return None; - } - out = small; - i = 1; - } else { - loop { - let shift = i << crate::digit::$Digit::BIT_SHIFT; - if i >= N || shift >= <$int>::BITS as usize { - break; - } - out |= self.digits[i] as $int << shift; - i += 1; - } - } - - #[allow(unused_comparisons)] - if out < 0 { - return None; - } - - while i < N { - if self.digits[i] != 0 { - return None; - } - i += 1; - } - - Some(out) - } - )* - }; + { $Digit: ident; $($name: ident -> $int: ty), * } => { + $( + #[inline] + fn $name(&self) -> Option<$int> { + let mut out = 0; + let mut i = 0; + if $Digit::BITS > <$int>::BITS { + let small = self.digits[i] as $int; + let trunc = small as $Digit; + if self.digits[i] != trunc { + return None; + } + out = small; + i = 1; + } else { + loop { + let shift = i << crate::digit::$Digit::BIT_SHIFT; + if i >= N || shift >= <$int>::BITS as usize { + break; + } + out |= self.digits[i] as $int << shift; + i += 1; + } + } + + #[allow(unused_comparisons)] + if out < 0 { + return None; + } + + while i < N { + if self.digits[i] != 0 { + return None; + } + i += 1; + } + + Some(out) + } + )* + }; } use crate::buint::cast::{decode_f32, decode_f64, u32_bits, u64_bits}; @@ -152,114 +152,112 @@ macro_rules! numtraits { //} //impl_const! { - impl Integer for $BUint { - #[inline] - fn div_floor(&self, other: &Self) -> Self { - *self / *other - } + impl Integer for $BUint { + #[inline] + fn div_floor(&self, other: &Self) -> Self { + *self / *other + } - #[inline] - fn mod_floor(&self, other: &Self) -> Self { - *self % *other - } + #[inline] + fn mod_floor(&self, other: &Self) -> Self { + *self % *other + } - #[inline] - fn gcd(&self, other: &Self) -> Self { - // Paul E. Black, "binary GCD", in Dictionary of Algorithms and Data Structures [online], Paul E. Black, ed. 2 November 2020. (accessed 15th June 2022) Available from: https://www.nist.gov/dads/HTML/binaryGCD.html - // https://en.wikipedia.org/wiki/Binary_GCD_algorithm#Implementation + #[inline] + fn gcd(&self, other: &Self) -> Self { + // Paul E. Black, "binary GCD", in Dictionary of Algorithms and Data Structures [online], Paul E. Black, ed. 2 November 2020. (accessed 15th June 2022) Available from: https://www.nist.gov/dads/HTML/binaryGCD.html + // https://en.wikipedia.org/wiki/Binary_GCD_algorithm#Implementation - let (mut a, mut b) = (*self, *other); - if a.is_zero() { - return b; + 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(); + // Normalise `a` and `b` so that both of them has no leading zeros, so both must be odd. + unsafe { + a = Self::unchecked_shr_internal(a, a_tz); + b = Self::unchecked_shr_internal(b, b_tz); + } + + if b_tz > a_tz { + // Ensure `a_tz >= b_tz` + core::mem::swap(&mut a_tz, &mut b_tz); + } + loop { + if a < b { + // Ensure `a >= b` + core::mem::swap(&mut a, &mut b); } - if b.is_zero() { - return a; + a -= b; + if a.is_zero() { + return unsafe { Self::unchecked_shl_internal(b, b_tz) }; } - let mut a_tz = a.trailing_zeros(); - let mut b_tz = b.trailing_zeros(); - // Normalise `a` and `b` so that both of them has no leading zeros, so both must be odd. unsafe { - a = Self::unchecked_shr_internal(a, a_tz); - b = Self::unchecked_shr_internal(b, b_tz); - } - - if b_tz > a_tz { - // Ensure `a_tz >= b_tz` - core::mem::swap(&mut a_tz, &mut b_tz); - } - loop { - if a < b { - // Ensure `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 = Self::unchecked_shr_internal(a, a.trailing_zeros()); - } + a = Self::unchecked_shr_internal(a, a.trailing_zeros()); } } + } - #[inline] - fn lcm(&self, other: &Self) -> Self { - self.div_floor(&self.gcd(other)) * *other - } + #[inline] + fn lcm(&self, other: &Self) -> Self { + self.div_floor(&self.gcd(other)) * *other + } - #[inline] - fn divides(&self, other: &Self) -> bool { - self.is_multiple_of(other) - } + #[inline] + fn divides(&self, other: &Self) -> bool { + self.is_multiple_of(other) + } - #[inline] - fn is_multiple_of(&self, other: &Self) -> bool { - self.mod_floor(other).is_zero() - } + #[inline] + fn is_multiple_of(&self, other: &Self) -> bool { + self.mod_floor(other).is_zero() + } - #[inline] - fn is_even(&self) -> bool { - self.digits[0] & 1 == 0 - } + #[inline] + fn is_even(&self) -> bool { + self.digits[0] & 1 == 0 + } - #[inline] - fn is_odd(&self) -> bool { - self.digits[0] & 1 == 1 - } + #[inline] + fn is_odd(&self) -> bool { + self.digits[0] & 1 == 1 + } - #[inline] - fn div_rem(&self, rhs: &Self) -> (Self, Self) { - Self::div_rem(*self, *rhs) - } + #[inline] + fn div_rem(&self, rhs: &Self) -> (Self, Self) { + Self::div_rem(*self, *rhs) } + } //} //impl_const! { - impl PrimInt for $BUint { - crate::int::numtraits::prim_int_methods!(); + impl PrimInt for $BUint { + crate::int::numtraits::prim_int_methods!(); - #[inline] - fn signed_shl(self, n: u32) -> Self { - self << n - } + #[inline] + fn signed_shl(self, n: u32) -> Self { + self << n + } - #[inline] - fn signed_shr(self, n: u32) -> Self { - ($BInt::from_bits(self) >> n).to_bits() - } + #[inline] + fn signed_shr(self, n: u32) -> Self { + ($BInt::from_bits(self) >> n).to_bits() + } - #[inline] - fn unsigned_shl(self, n: u32) -> Self { - self << n - } + #[inline] + fn unsigned_shl(self, n: u32) -> Self { + self << n + } - #[inline] - fn unsigned_shr(self, n: u32) -> Self { - self >> n - } + #[inline] + fn unsigned_shr(self, n: u32) -> Self { + self >> n } + } //} macro_rules! check_zero_or_one { @@ -423,9 +421,9 @@ macro_rules! numtraits { paste::paste! { mod [<$Digit _digit_tests>] { use crate::test::types::big_types::$Digit::*; - use crate::test::types::utest; + use crate::test::types::utest; - crate::int::numtraits::tests!(utest); + crate::int::numtraits::tests!(utest); } } }; diff --git a/src/buint/ops.rs b/src/buint/ops.rs index 10c457d..e3111e2 100644 --- a/src/buint/ops.rs +++ b/src/buint/ops.rs @@ -83,46 +83,46 @@ macro_rules! ops { self.div_rem_digit(rhs).0 } } - - impl_const! { - impl const Not for $BUint { - type Output = Self; - - #[inline] - fn not(self) -> Self { - Self::not(self) - } - } - } - - impl_const! { - impl const Rem for $BUint { - type Output = Self; - - #[inline] - fn rem(self, rhs: Self) -> Self { - Self::rem(self, rhs) - } - } - } - - impl_const! { - impl const Rem<$Digit> for $BUint { - type Output = $Digit; - - #[inline] - fn rem(self, rhs: $Digit) -> $Digit { - self.div_rem_digit(rhs).1 - } - } - } - } + + impl_const! { + impl const Not for $BUint { + type Output = Self; + + #[inline] + fn not(self) -> Self { + Self::not(self) + } + } + } + + impl_const! { + impl const Rem for $BUint { + type Output = Self; + + #[inline] + fn rem(self, rhs: Self) -> Self { + Self::rem(self, rhs) + } + } + } + + impl_const! { + impl const Rem<$Digit> for $BUint { + type Output = $Digit; + + #[inline] + fn rem(self, rhs: $Digit) -> $Digit { + self.div_rem_digit(rhs).1 + } + } + } + } crate::int::ops::impls!($BUint, $BUint, $BInt); #[cfg(test)] paste::paste! { - mod [<$Digit _digit_tests>] { + mod [<$Digit _digit_tests>] { use super::*; use crate::test::{test_bignum, types::utest}; use crate::test::types::big_types::$Digit::*; diff --git a/src/buint/overflowing.rs b/src/buint/overflowing.rs index a16303a..78931f4 100644 --- a/src/buint/overflowing.rs +++ b/src/buint/overflowing.rs @@ -118,40 +118,38 @@ macro_rules! overflowing { pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { self.overflowing_rem(rhs) } - } - - #[doc = doc::overflowing::overflowing_neg!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_neg(self) -> (Self, bool) { - let (a, b) = (self.not()).overflowing_add(Self::ONE); - (a, !b) - } - - crate::nightly::const_fns! { - #[doc = doc::overflowing::overflowing_shl!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) { - unsafe { - if rhs >= Self::BITS { - (Self::unchecked_shl_internal(self, rhs & (Self::BITS - 1)), true) - } else { - (Self::unchecked_shl_internal(self, rhs), false) - } + } + + #[doc = doc::overflowing::overflowing_neg!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_neg(self) -> (Self, bool) { + let (a, b) = (self.not()).overflowing_add(Self::ONE); + (a, !b) + } + + #[doc = doc::overflowing::overflowing_shl!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) { + unsafe { + if rhs >= Self::BITS { + (Self::unchecked_shl_internal(self, rhs & (Self::BITS - 1)), true) + } else { + (Self::unchecked_shl_internal(self, rhs), false) } } + } - #[doc = doc::overflowing::overflowing_shr!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) { - unsafe { - if rhs >= Self::BITS { - (Self::unchecked_shr_internal(self, rhs & (Self::BITS - 1)), true) - } else { - (Self::unchecked_shr_internal(self, rhs), false) - } + #[doc = doc::overflowing::overflowing_shr!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) { + unsafe { + if rhs >= Self::BITS { + (Self::unchecked_shr_internal(self, rhs & (Self::BITS - 1)), true) + } else { + (Self::unchecked_shr_internal(self, rhs), false) } } } @@ -183,7 +181,7 @@ macro_rules! overflowing { #[cfg(test)] paste::paste! { - mod [<$Digit _digit_tests>] { + mod [<$Digit _digit_tests>] { use crate::test::{test_bignum, types::utest}; use crate::test::types::big_types::$Digit::*; diff --git a/src/buint/radix.rs b/src/buint/radix.rs index 5e9da3d..d18a9f9 100644 --- a/src/buint/radix.rs +++ b/src/buint/radix.rs @@ -36,7 +36,7 @@ macro_rules! radix { ($BUint: ident, $BInt: ident, $Digit: ident) => { #[doc = doc::radix::impl_desc!($BUint)] impl $BUint { - #[inline] + #[inline] const fn radix_base(radix: u32) -> ($Digit, usize) { let mut power: usize = 1; let radix = radix as $Digit; @@ -52,7 +52,7 @@ macro_rules! radix { } } - #[inline] + #[inline] const fn radix_base_half(radix: u32) -> ($Digit, usize) { const HALF_BITS_MAX: $Digit = $Digit::MAX >> ($Digit::BITS / 2); @@ -94,76 +94,76 @@ macro_rules! radix { crate::nightly::ok!(Self::from_str_radix(s, radix)) } - crate::nightly::const_fns! { - /// Converts a slice of big-endian digits in the given radix to an integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 256 inclusive. - /// - /// # Examples - /// - /// ``` - /// use bnum::types::U512; - /// - /// let n = U512::from(34598748526857897975u128); - /// let digits = n.to_radix_be(12); - /// assert_eq!(Some(n), U512::from_radix_be(&digits, 12)); - /// ``` - #[inline] - pub const fn from_radix_be(buf: &[u8], radix: u32) -> Option { - assert_range!(radix, 256); - if buf.is_empty() { - return Some(Self::ZERO); - } - if radix == 256 { - return Self::from_be_slice(buf); - } - - crate::nightly::ok!(Self::from_buf_radix_internal::(buf, radix, false)) - } - - /// Converts a slice of little-endian digits in the given radix to an integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 256 inclusive. - /// - /// # Examples - /// - /// ``` - /// use bnum::types::U512; - /// - /// let n = U512::from(109837459878951038945798u128); - /// let digits = n.to_radix_le(15); - /// assert_eq!(Some(n), U512::from_radix_le(&digits, 15)); - /// ``` - #[inline] - pub const fn from_radix_le(buf: &[u8], radix: u32) -> Option { - assert_range!(radix, 256); - if buf.is_empty() { - return Some(Self::ZERO); - } - if radix == 256 { - return Self::from_le_slice(buf); - } - - crate::nightly::ok!(Self::from_buf_radix_internal::(buf, radix, false)) - } - } - - #[inline] + crate::nightly::const_fns! { + /// Converts a slice of big-endian digits in the given radix to an integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 256 inclusive. + /// + /// # Examples + /// + /// ``` + /// use bnum::types::U512; + /// + /// let n = U512::from(34598748526857897975u128); + /// let digits = n.to_radix_be(12); + /// assert_eq!(Some(n), U512::from_radix_be(&digits, 12)); + /// ``` + #[inline] + pub const fn from_radix_be(buf: &[u8], radix: u32) -> Option { + assert_range!(radix, 256); + if buf.is_empty() { + return Some(Self::ZERO); + } + if radix == 256 { + return Self::from_be_slice(buf); + } + + crate::nightly::ok!(Self::from_buf_radix_internal::(buf, radix, false)) + } + + /// Converts a slice of little-endian digits in the given radix to an integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`. + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 256 inclusive. + /// + /// # Examples + /// + /// ``` + /// use bnum::types::U512; + /// + /// let n = U512::from(109837459878951038945798u128); + /// let digits = n.to_radix_le(15); + /// assert_eq!(Some(n), U512::from_radix_le(&digits, 15)); + /// ``` + #[inline] + pub const fn from_radix_le(buf: &[u8], radix: u32) -> Option { + assert_range!(radix, 256); + if buf.is_empty() { + return Some(Self::ZERO); + } + if radix == 256 { + return Self::from_le_slice(buf); + } + + crate::nightly::ok!(Self::from_buf_radix_internal::(buf, radix, false)) + } + } + + #[inline] const fn byte_to_digit(byte: u8) -> u8 { - if FROM_STR { - match byte { - b'0'..=b'9' => byte - b'0', - b'a'..=b'z' => byte - b'a' + 10, - b'A'..=b'Z' => byte - b'A' + 10, - _ => u8::MAX, - } - } else { - byte - } + if FROM_STR { + match byte { + b'0'..=b'9' => byte - b'0', + b'a'..=b'z' => byte - b'a' + 10, + b'A'..=b'Z' => byte - b'A' + 10, + _ => u8::MAX, + } + } else { + byte + } } /// Converts a string slice in a given base to an integer. @@ -185,228 +185,228 @@ macro_rules! radix { /// /// assert_eq!(U512::from_str_radix("A", 16), Ok(U512::from(10u128))); /// ``` - #[inline] - pub const fn from_str_radix(src: &str, radix: u32) -> Result { - assert_range!(radix, 36); - if src.is_empty() { + #[inline] + pub const fn from_str_radix(src: &str, radix: u32) -> Result { + assert_range!(radix, 36); + if src.is_empty() { return Err(ParseIntError { kind: IntErrorKind::Empty, }); } - let buf = src.as_bytes(); - let leading_plus = buf[0] == b'+'; - Self::from_buf_radix_internal::(buf, radix, leading_plus) - } - - #[doc = doc::radix::parse_str_radix!($BUint)] - #[inline] - pub const fn parse_str_radix(src: &str, radix: u32) -> Self { - match Self::from_str_radix(src, radix) { - Ok(n) => n, - Err(e) => panic!("{}", e.description()), - } - } - - pub(crate) const fn from_buf_radix_internal(buf: &[u8], radix: u32, leading_sign: bool) -> Result { - if leading_sign && buf.len() == 1 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - let input_digits_len = if leading_sign { - buf.len() - 1 - } else { - buf.len() - }; - - match radix { - 2 | 4 | 16 | 256 => { - let mut out = Self::ZERO; - let base_digits_per_digit = (digit::$Digit::BITS_U8 / ilog2(radix)) as usize; - let full_digits = input_digits_len / base_digits_per_digit as usize; - let remaining_digits = input_digits_len % base_digits_per_digit as usize; - if full_digits > N || full_digits == N && remaining_digits != 0 { - return Err(ParseIntError { - kind: IntErrorKind::PosOverflow, - }); - } - - let radix_u8 = radix as u8; - let log2r = ilog2(radix); - - let mut i = 0; - while i < full_digits { - let mut j = 0; - while j < base_digits_per_digit { - let idx = if BE { - buf.len() - 1 - (i * base_digits_per_digit + j) - } else { - i * base_digits_per_digit + j - }; - let d = Self::byte_to_digit::(buf[idx]); - if d >= radix_u8 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - out.digits[i] |= (d as $Digit) << (j * log2r as usize); - j += 1; - } - i += 1; - } - let mut j = 0; - while j < remaining_digits { - let idx = if BE { - buf.len() - 1 - (i * base_digits_per_digit + j) - } else { - i * base_digits_per_digit + j - }; - let d = Self::byte_to_digit::(buf[idx]); - if d >= radix_u8 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - out.digits[i] |= (d as $Digit) << (j * log2r as usize); - j += 1; - } - Ok(out) - }, - 8 | 32 | 64 | 128 => { - let mut out = Self::ZERO; - let radix_u8 = radix as u8; - let log2r = ilog2(radix); - - let mut index = 0; - let mut shift = 0; - - let mut i = buf.len(); - let stop_index = if leading_sign { 1 } else { 0 }; - while i > stop_index { - i -= 1; - let idx = if BE { - i - } else { - buf.len() - 1 - i - }; - let d = Self::byte_to_digit::(buf[idx]); - if d >= radix_u8 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - out.digits[index] |= (d as $Digit) << shift; - shift += log2r; - if shift >= digit::$Digit::BITS_U8 { - shift -= digit::$Digit::BITS_U8; - let carry = (d as $Digit) >> (log2r - shift); - index += 1; - if index == N { - if carry != 0 { - return Err(ParseIntError { - kind: IntErrorKind::PosOverflow, - }); - } - while i > stop_index { - i -= 1; - let idx = if BE { - i - } else { - buf.len() - 1 - i - }; - let d = Self::byte_to_digit::(buf[idx]); - if d != 0 { - return Err(ParseIntError { - kind: IntErrorKind::PosOverflow, - }); - } - } - return Ok(out); - } else { - out.digits[index] = carry; - } - } - } - Ok(out) - }, - _ => { - let (base, power) = Self::radix_base(radix); - let r = input_digits_len % power; - let split = if r == 0 { power } else { r }; - let radix_u8 = radix as u8; - let mut out = Self::ZERO; - let mut first: $Digit = 0; - let mut i = if leading_sign { - 1 - } else { - 0 - }; - while i < if leading_sign { split + 1 } else { split } { - let idx = if BE { - i - } else { - buf.len() - 1 - i - }; - let d = Self::byte_to_digit::(buf[idx]); - if d >= radix_u8 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - first = first * (radix as $Digit) + d as $Digit; - i += 1; - } - out.digits[0] = first; - let mut start = i; - while start < buf.len() { - let end = start + power; - - let mut carry = 0; - let mut j = 0; - while j < N { - let (low, high) = digit::$Digit::carrying_mul(out.digits[j], base, carry, 0); - carry = high; - out.digits[j] = low; - j += 1; - } - if carry != 0 { - return Err(ParseIntError { - kind: IntErrorKind::PosOverflow, - }); - } - - let mut n = 0; - j = start; - while j < end && j < buf.len() { - let idx = if BE { - j - } else { - buf.len() - 1 - j - }; - let d = Self::byte_to_digit::(buf[idx]); - if d >= radix_u8 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - n = n * (radix as $Digit) + d as $Digit; - j += 1; - } - - out = match out.checked_add(Self::from_digit(n)) { - Some(out) => out, - None => { - return Err(ParseIntError { - kind: IntErrorKind::PosOverflow, - }) - } - }; - start = end; - } - Ok(out) - } - } - } + let buf = src.as_bytes(); + let leading_plus = buf[0] == b'+'; + Self::from_buf_radix_internal::(buf, radix, leading_plus) + } + + #[doc = doc::radix::parse_str_radix!($BUint)] + #[inline] + pub const fn parse_str_radix(src: &str, radix: u32) -> Self { + match Self::from_str_radix(src, radix) { + Ok(n) => n, + Err(e) => panic!("{}", e.description()), + } + } + + pub(crate) const fn from_buf_radix_internal(buf: &[u8], radix: u32, leading_sign: bool) -> Result { + if leading_sign && buf.len() == 1 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + let input_digits_len = if leading_sign { + buf.len() - 1 + } else { + buf.len() + }; + + match radix { + 2 | 4 | 16 | 256 => { + let mut out = Self::ZERO; + let base_digits_per_digit = (digit::$Digit::BITS_U8 / ilog2(radix)) as usize; + let full_digits = input_digits_len / base_digits_per_digit as usize; + let remaining_digits = input_digits_len % base_digits_per_digit as usize; + if full_digits > N || full_digits == N && remaining_digits != 0 { + return Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }); + } + + let radix_u8 = radix as u8; + let log2r = ilog2(radix); + + let mut i = 0; + while i < full_digits { + let mut j = 0; + while j < base_digits_per_digit { + let idx = if BE { + buf.len() - 1 - (i * base_digits_per_digit + j) + } else { + i * base_digits_per_digit + j + }; + let d = Self::byte_to_digit::(buf[idx]); + if d >= radix_u8 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + out.digits[i] |= (d as $Digit) << (j * log2r as usize); + j += 1; + } + i += 1; + } + let mut j = 0; + while j < remaining_digits { + let idx = if BE { + buf.len() - 1 - (i * base_digits_per_digit + j) + } else { + i * base_digits_per_digit + j + }; + let d = Self::byte_to_digit::(buf[idx]); + if d >= radix_u8 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + out.digits[i] |= (d as $Digit) << (j * log2r as usize); + j += 1; + } + Ok(out) + }, + 8 | 32 | 64 | 128 => { + let mut out = Self::ZERO; + let radix_u8 = radix as u8; + let log2r = ilog2(radix); + + let mut index = 0; + let mut shift = 0; + + let mut i = buf.len(); + let stop_index = if leading_sign { 1 } else { 0 }; + while i > stop_index { + i -= 1; + let idx = if BE { + i + } else { + buf.len() - 1 - i + }; + let d = Self::byte_to_digit::(buf[idx]); + if d >= radix_u8 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + out.digits[index] |= (d as $Digit) << shift; + shift += log2r; + if shift >= digit::$Digit::BITS_U8 { + shift -= digit::$Digit::BITS_U8; + let carry = (d as $Digit) >> (log2r - shift); + index += 1; + if index == N { + if carry != 0 { + return Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }); + } + while i > stop_index { + i -= 1; + let idx = if BE { + i + } else { + buf.len() - 1 - i + }; + let d = Self::byte_to_digit::(buf[idx]); + if d != 0 { + return Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }); + } + } + return Ok(out); + } else { + out.digits[index] = carry; + } + } + } + Ok(out) + }, + _ => { + let (base, power) = Self::radix_base(radix); + let r = input_digits_len % power; + let split = if r == 0 { power } else { r }; + let radix_u8 = radix as u8; + let mut out = Self::ZERO; + let mut first: $Digit = 0; + let mut i = if leading_sign { + 1 + } else { + 0 + }; + while i < if leading_sign { split + 1 } else { split } { + let idx = if BE { + i + } else { + buf.len() - 1 - i + }; + let d = Self::byte_to_digit::(buf[idx]); + if d >= radix_u8 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + first = first * (radix as $Digit) + d as $Digit; + i += 1; + } + out.digits[0] = first; + let mut start = i; + while start < buf.len() { + let end = start + power; + + let mut carry = 0; + let mut j = 0; + while j < N { + let (low, high) = digit::$Digit::carrying_mul(out.digits[j], base, carry, 0); + carry = high; + out.digits[j] = low; + j += 1; + } + if carry != 0 { + return Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }); + } + + let mut n = 0; + j = start; + while j < end && j < buf.len() { + let idx = if BE { + j + } else { + buf.len() - 1 - j + }; + let d = Self::byte_to_digit::(buf[idx]); + if d >= radix_u8 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + n = n * (radix as $Digit) + d as $Digit; + j += 1; + } + + out = match out.checked_add(Self::from_digit(n)) { + Some(out) => out, + None => { + return Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }) + } + }; + start = end; + } + Ok(out) + } + } + } /// Returns the integer as a string in the given radix. /// @@ -577,140 +577,140 @@ macro_rules! radix { } #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::{quickcheck_from_to_radix, test_bignum, self}; - use crate::$BUint; - use core::str::FromStr; - use crate::test::types::big_types::$Digit::*; - use crate::test::types::utest; - - test_bignum! { - function: ::from_str, - cases: [ - ("398475394875230495745"), - ("3984753948752304957423490785029749572977970985"), - ("12345💩👍"), - ("1234567890a") - ] - } - - test_bignum! { - function: ::from_str_radix, - cases: [ - ("+af7345asdofiuweor", 35u32), - ("+945hhdgi73945hjdfj", 32u32), - ("+3436847561345343455", 9u32), - ("+affe758457bc345540ac399", 16u32), - ("+affe758457bc345540ac39929334534ee34579234795", 17u32), - ("+3777777777777777777777777777777777777777777", 8u32), - ("+37777777777777777777777777777777777777777761", 8u32), - ("+1777777777777777777777", 8u32), - ("+17777777777777777777773", 8u32), - ("+2000000000000000000000", 8u32), - ("-234598734", 10u32), - ("g234ab", 16u32), - ("234£$2234", 15u32), - ("123456💯", 30u32), - ("3434💯34593487", 12u32), - ("💯34593487", 11u32), - ("12345678", 8u32), - ("abcdefw", 32u32), - ("1234ab", 11u32), - ("1234", 4u32), - ("010120101", 2u32), - ("10000000000000000", 16u32), - ("p8hrbe0mo0084i6vckj1tk7uvacnn4cm", 32u32) - ] - } - - quickcheck_from_to_radix!(utest, radix_be, 256); - quickcheck_from_to_radix!(utest, radix_le, 256); - quickcheck_from_to_radix!(utest, str_radix, 36); - - test::quickcheck_from_str_radix!(utest, "+" | ""); - test::quickcheck_from_str!(utest); - - #[test] - fn from_to_radix_le() { - let buf = &[ - 23, 100, 45, 58, 44, 56, 55, 100, 76, 54, 10, 100, 100, 100, 100, 100, 200, - 200, 200, 200, 255, 255, 255, 255, 255, 100, 100, 44, 60, 56, 48, 69, 160, 59, - 50, 50, 200, 250, 250, 250, 250, 250, 240, 120, - ]; - let u = $BUint::<100>::from_radix_le(buf, 256).unwrap(); - let v = u.to_radix_le(256); - assert_eq!(v, buf); - - let buf = &[34, 45, 32, 100, 53, 54, 65, 53, 0, 53]; - let option = $BUint::<100>::from_radix_le(buf, 99); - assert!(option.is_none()); - - let buf = &[ - 1, 0, 2, 3, 1, 0, 0, 2, 3, 1, 2, 3, 1, 0, 1, 2, 3, 1, 3, 1, 3, 1, 3, 2, 3, 2, - 3, 1, 3, 2, 3, 1, 3, 2, 3, 2, 3, 1, 2, 3, 0, 0, 0, 2, 3, - ]; - let u = $BUint::<100>::from_radix_le(buf, 4).unwrap(); - let v = u.to_radix_le(4); - assert_eq!(v, buf); - } - #[test] - fn from_to_radix_be() { - let buf = &[34, 57, 100, 184, 54, 40, 78, 10, 5, 200, 45, 67]; - let u = $BUint::<100>::from_radix_be(buf, 201).unwrap(); - let v = u.to_radix_be(201); - assert_eq!(v, buf); - - let buf = &[ - 1, 0, 2, 3, 1, 0, 0, 2, 3, 1, 2, 3, 1, 0, 1, 2, 3, 1, 3, 1, 3, 1, 3, 2, 3, 2, - 3, 1, 3, 2, 3, 1, 3, 2, 3, 2, 3, 1, 2, 3, 0, 0, 0, 2, 3, - ]; - let u = $BUint::<100>::from_radix_be(buf, 4).unwrap(); - let v = u.to_radix_be(4); - assert_eq!(v, buf); - - let buf = &[100, 4, 0, 54, 45, 20, 200, 43]; - let option = $BUint::<100>::from_radix_le(buf, 150); - assert!(option.is_none()); - - let buf = &[ - 9, 5, 1, 5, 5, 1, 5, 9, 8, 7, 6, 4, 2, 5, 4, 2, 3, 4, 9, 0, 1, 2, 3, 4, 5, 1, - 6, 6, 1, 6, 7, 1, 6, 5, 1, 5, 1, 6, 1, 7, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 1, - 7, 1, 7, 1, 7, 1, 7, 5, - ]; - let u = $BUint::<100>::from_radix_be(buf, 10).unwrap(); - let v = u.to_radix_be(10); - assert_eq!(v, buf); - } - #[test] - fn from_to_str_radix() { - let src = "34985789aasdfhoehdghjkh93485797df"; - let u = $BUint::<100>::from_str_radix(src, 32).unwrap(); - let v = u.to_str_radix(32); - assert_eq!(v, src); - - let src = "934579gfhjh394hdkg9845798"; - let result = $BUint::<100>::from_str_radix(src, 18); - assert!(result.is_err()); - - let src = "120102301230102301230102030120321012"; - let u = $BUint::<100>::from_str_radix(src, 4).unwrap(); - assert_eq!(u.to_str_radix(4), src); - } - #[test] - fn parse_bytes() { - let src = "134957dkbhadoinegrhi983475hdgkhgdhiu3894hfd"; - let u = $BUint::<100>::parse_bytes(src.as_bytes(), 35).unwrap(); - let v = $BUint::<100>::from_str_radix(src, 35).unwrap(); - assert_eq!(u, v); - assert_eq!(v.to_str_radix(35), src); - - let bytes = b"345977fsuudf0350845"; - let option = $BUint::<100>::parse_bytes(bytes, 20); - assert!(option.is_none()); - } - } - } + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::{quickcheck_from_to_radix, test_bignum, self}; + use crate::$BUint; + use core::str::FromStr; + use crate::test::types::big_types::$Digit::*; + use crate::test::types::utest; + + test_bignum! { + function: ::from_str, + cases: [ + ("398475394875230495745"), + ("3984753948752304957423490785029749572977970985"), + ("12345💩👍"), + ("1234567890a") + ] + } + + test_bignum! { + function: ::from_str_radix, + cases: [ + ("+af7345asdofiuweor", 35u32), + ("+945hhdgi73945hjdfj", 32u32), + ("+3436847561345343455", 9u32), + ("+affe758457bc345540ac399", 16u32), + ("+affe758457bc345540ac39929334534ee34579234795", 17u32), + ("+3777777777777777777777777777777777777777777", 8u32), + ("+37777777777777777777777777777777777777777761", 8u32), + ("+1777777777777777777777", 8u32), + ("+17777777777777777777773", 8u32), + ("+2000000000000000000000", 8u32), + ("-234598734", 10u32), + ("g234ab", 16u32), + ("234£$2234", 15u32), + ("123456💯", 30u32), + ("3434💯34593487", 12u32), + ("💯34593487", 11u32), + ("12345678", 8u32), + ("abcdefw", 32u32), + ("1234ab", 11u32), + ("1234", 4u32), + ("010120101", 2u32), + ("10000000000000000", 16u32), + ("p8hrbe0mo0084i6vckj1tk7uvacnn4cm", 32u32) + ] + } + + quickcheck_from_to_radix!(utest, radix_be, 256); + quickcheck_from_to_radix!(utest, radix_le, 256); + quickcheck_from_to_radix!(utest, str_radix, 36); + + test::quickcheck_from_str_radix!(utest, "+" | ""); + test::quickcheck_from_str!(utest); + + #[test] + fn from_to_radix_le() { + let buf = &[ + 23, 100, 45, 58, 44, 56, 55, 100, 76, 54, 10, 100, 100, 100, 100, 100, 200, + 200, 200, 200, 255, 255, 255, 255, 255, 100, 100, 44, 60, 56, 48, 69, 160, 59, + 50, 50, 200, 250, 250, 250, 250, 250, 240, 120, + ]; + let u = $BUint::<100>::from_radix_le(buf, 256).unwrap(); + let v = u.to_radix_le(256); + assert_eq!(v, buf); + + let buf = &[34, 45, 32, 100, 53, 54, 65, 53, 0, 53]; + let option = $BUint::<100>::from_radix_le(buf, 99); + assert!(option.is_none()); + + let buf = &[ + 1, 0, 2, 3, 1, 0, 0, 2, 3, 1, 2, 3, 1, 0, 1, 2, 3, 1, 3, 1, 3, 1, 3, 2, 3, 2, + 3, 1, 3, 2, 3, 1, 3, 2, 3, 2, 3, 1, 2, 3, 0, 0, 0, 2, 3, + ]; + let u = $BUint::<100>::from_radix_le(buf, 4).unwrap(); + let v = u.to_radix_le(4); + assert_eq!(v, buf); + } + #[test] + fn from_to_radix_be() { + let buf = &[34, 57, 100, 184, 54, 40, 78, 10, 5, 200, 45, 67]; + let u = $BUint::<100>::from_radix_be(buf, 201).unwrap(); + let v = u.to_radix_be(201); + assert_eq!(v, buf); + + let buf = &[ + 1, 0, 2, 3, 1, 0, 0, 2, 3, 1, 2, 3, 1, 0, 1, 2, 3, 1, 3, 1, 3, 1, 3, 2, 3, 2, + 3, 1, 3, 2, 3, 1, 3, 2, 3, 2, 3, 1, 2, 3, 0, 0, 0, 2, 3, + ]; + let u = $BUint::<100>::from_radix_be(buf, 4).unwrap(); + let v = u.to_radix_be(4); + assert_eq!(v, buf); + + let buf = &[100, 4, 0, 54, 45, 20, 200, 43]; + let option = $BUint::<100>::from_radix_le(buf, 150); + assert!(option.is_none()); + + let buf = &[ + 9, 5, 1, 5, 5, 1, 5, 9, 8, 7, 6, 4, 2, 5, 4, 2, 3, 4, 9, 0, 1, 2, 3, 4, 5, 1, + 6, 6, 1, 6, 7, 1, 6, 5, 1, 5, 1, 6, 1, 7, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 1, + 7, 1, 7, 1, 7, 1, 7, 5, + ]; + let u = $BUint::<100>::from_radix_be(buf, 10).unwrap(); + let v = u.to_radix_be(10); + assert_eq!(v, buf); + } + #[test] + fn from_to_str_radix() { + let src = "34985789aasdfhoehdghjkh93485797df"; + let u = $BUint::<100>::from_str_radix(src, 32).unwrap(); + let v = u.to_str_radix(32); + assert_eq!(v, src); + + let src = "934579gfhjh394hdkg9845798"; + let result = $BUint::<100>::from_str_radix(src, 18); + assert!(result.is_err()); + + let src = "120102301230102301230102030120321012"; + let u = $BUint::<100>::from_str_radix(src, 4).unwrap(); + assert_eq!(u.to_str_radix(4), src); + } + #[test] + fn parse_bytes() { + let src = "134957dkbhadoinegrhi983475hdgkhgdhiu3894hfd"; + let u = $BUint::<100>::parse_bytes(src.as_bytes(), 35).unwrap(); + let v = $BUint::<100>::from_str_radix(src, 35).unwrap(); + assert_eq!(u, v); + assert_eq!(v.to_str_radix(35), src); + + let bytes = b"345977fsuudf0350845"; + let option = $BUint::<100>::parse_bytes(bytes, 20); + assert!(option.is_none()); + } + } + } }; } diff --git a/src/buint/saturating.rs b/src/buint/saturating.rs index a0a1554..86161cd 100644 --- a/src/buint/saturating.rs +++ b/src/buint/saturating.rs @@ -74,7 +74,7 @@ macro_rules! saturating { #[cfg(test)] paste::paste! { - mod [<$Digit _digit_tests>] { + mod [<$Digit _digit_tests>] { use crate::test::{test_bignum, types::*}; use crate::test::types::big_types::$Digit::*; diff --git a/src/buint/wrapping.rs b/src/buint/wrapping.rs index 7e3fee1..4e25e5a 100644 --- a/src/buint/wrapping.rs +++ b/src/buint/wrapping.rs @@ -3,172 +3,170 @@ use crate::ExpType; use crate::{doc, errors}; macro_rules! wrapping { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::wrapping::impl_desc!()] - impl $BUint { - #[doc = doc::wrapping::wrapping_add!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { - self.overflowing_add(rhs).0 - } - - #[doc = doc::wrapping::wrapping_add_signed!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_add_signed(self, rhs: $BInt) -> Self { - self.overflowing_add_signed(rhs).0 - } - - #[doc = doc::wrapping::wrapping_sub!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - self.overflowing_sub(rhs).0 - } - - #[doc = doc::wrapping::wrapping_mul!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - self.overflowing_mul(rhs).0 - } - - crate::nightly::const_fns! { - #[doc = doc::wrapping::wrapping_div!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - option_expect!(self.checked_div(rhs), errors::err_msg!("attempt to divide by zero")) - } - - #[doc = doc::wrapping::wrapping_div_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self.wrapping_div(rhs) - } - - #[doc = doc::wrapping::wrapping_rem!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - option_expect!(self.checked_rem(rhs), errors::err_msg!("attempt to calculate the remainder with a divisor of zero")) - } - - #[doc = doc::wrapping::wrapping_rem_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { - self.wrapping_rem(rhs) - } - } - - #[doc = doc::wrapping::wrapping_neg!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } - - crate::nightly::const_fns! { - #[doc = doc::wrapping::wrapping_shl!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_shl(self, rhs: ExpType) -> Self { - self.overflowing_shl(rhs).0 - } - - #[doc = doc::wrapping::wrapping_shr!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_shr(self, rhs: ExpType) -> Self { - self.overflowing_shr(rhs).0 - } - } - - #[doc = doc::wrapping::wrapping_pow!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_pow(mut self, mut pow: ExpType) -> Self { - // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method - if pow == 0 { - return Self::ONE; - } - let mut y = Self::ONE; - while pow > 1 { - if pow & 1 == 1 { - y = self.wrapping_mul(y); - } - self = self.wrapping_mul(self); - pow >>= 1; - } - self.wrapping_mul(y) - } - - #[doc = doc::wrapping::wrapping_next_power_of_two!(U 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_next_power_of_two(self) -> Self { - match self.checked_next_power_of_two() { - Some(int) => int, - None => Self::ZERO, - } - } - } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - use crate::test::{test_bignum, types::utest}; - - test_bignum! { - function: ::wrapping_add(a: utest, b: utest) - } - test_bignum! { - function: ::wrapping_sub(a: utest, b: utest) - } - test_bignum! { - function: ::wrapping_mul(a: utest, b: utest) - } - test_bignum! { - function: ::wrapping_div(a: utest, b: utest), - skip: b == 0 - } - test_bignum! { - function: ::wrapping_div_euclid(a: utest, b: utest), - skip: b == 0 - } - test_bignum! { - function: ::wrapping_rem(a: utest, b: utest), - skip: b == 0 - } - test_bignum! { - function: ::wrapping_rem_euclid(a: utest, b: utest), - skip: b == 0 - } - test_bignum! { - function: ::wrapping_neg(a: utest) - } - test_bignum! { - function: ::wrapping_shl(a: utest, b: u16) - } - test_bignum! { - function: ::wrapping_shr(a: utest, b: u16) - } - test_bignum! { - function: ::wrapping_pow(a: utest, b: u16) - } - test_bignum! { - function: ::wrapping_next_power_of_two(a: utest), - cases: [ - (utest::MAX) - ] - } - } - } - }; + ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[doc = doc::wrapping::impl_desc!()] + impl $BUint { + #[doc = doc::wrapping::wrapping_add!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_add(self, rhs: Self) -> Self { + self.overflowing_add(rhs).0 + } + + #[doc = doc::wrapping::wrapping_add_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_add_signed(self, rhs: $BInt) -> Self { + self.overflowing_add_signed(rhs).0 + } + + #[doc = doc::wrapping::wrapping_sub!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + self.overflowing_sub(rhs).0 + } + + #[doc = doc::wrapping::wrapping_mul!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + self.overflowing_mul(rhs).0 + } + + crate::nightly::const_fns! { + #[doc = doc::wrapping::wrapping_div!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + option_expect!(self.checked_div(rhs), errors::err_msg!("attempt to divide by zero")) + } + + #[doc = doc::wrapping::wrapping_div_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self.wrapping_div(rhs) + } + + #[doc = doc::wrapping::wrapping_rem!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + option_expect!(self.checked_rem(rhs), errors::err_msg!("attempt to calculate the remainder with a divisor of zero")) + } + + #[doc = doc::wrapping::wrapping_rem_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self.wrapping_rem(rhs) + } + } + + #[doc = doc::wrapping::wrapping_neg!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + + #[doc = doc::wrapping::wrapping_shl!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_shl(self, rhs: ExpType) -> Self { + self.overflowing_shl(rhs).0 + } + + #[doc = doc::wrapping::wrapping_shr!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_shr(self, rhs: ExpType) -> Self { + self.overflowing_shr(rhs).0 + } + + #[doc = doc::wrapping::wrapping_pow!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_pow(mut self, mut pow: ExpType) -> Self { + // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method + if pow == 0 { + return Self::ONE; + } + let mut y = Self::ONE; + while pow > 1 { + if pow & 1 == 1 { + y = self.wrapping_mul(y); + } + self = self.wrapping_mul(self); + pow >>= 1; + } + self.wrapping_mul(y) + } + + #[doc = doc::wrapping::wrapping_next_power_of_two!(U 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_next_power_of_two(self) -> Self { + match self.checked_next_power_of_two() { + Some(int) => int, + None => Self::ZERO, + } + } + } + + #[cfg(test)] + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; + use crate::test::{test_bignum, types::utest}; + + test_bignum! { + function: ::wrapping_add(a: utest, b: utest) + } + test_bignum! { + function: ::wrapping_sub(a: utest, b: utest) + } + test_bignum! { + function: ::wrapping_mul(a: utest, b: utest) + } + test_bignum! { + function: ::wrapping_div(a: utest, b: utest), + skip: b == 0 + } + test_bignum! { + function: ::wrapping_div_euclid(a: utest, b: utest), + skip: b == 0 + } + test_bignum! { + function: ::wrapping_rem(a: utest, b: utest), + skip: b == 0 + } + test_bignum! { + function: ::wrapping_rem_euclid(a: utest, b: utest), + skip: b == 0 + } + test_bignum! { + function: ::wrapping_neg(a: utest) + } + test_bignum! { + function: ::wrapping_shl(a: utest, b: u16) + } + test_bignum! { + function: ::wrapping_shr(a: utest, b: u16) + } + test_bignum! { + function: ::wrapping_pow(a: utest, b: u16) + } + test_bignum! { + function: ::wrapping_next_power_of_two(a: utest), + cases: [ + (utest::MAX) + ] + } + } + } + }; } crate::macro_impl!(wrapping); diff --git a/src/cast.rs b/src/cast.rs index 8b30791..5c2f48a 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -13,15 +13,15 @@ pub(crate) trait CastTo { } macro_rules! as_trait_doc { - () => { + () => { "Trait which allows panic-free casting between numeric types. The behavior matches the behavior of the `as` conversion operator between primitive integers. This trait can be used to convert between bnum's integer types, as well as between bnum's integer types and Rust's primitive integers. Conversions between Rust's primitive integers themselves are also defined for consistency." - }; + }; } macro_rules! as_method_doc { - () => { + () => { "Casts `self` to type `T`. The [semantics of numeric casting](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics) with the `as` operator are followed, so `::as_::` can be used in the same way as `T as U` for numeric conversions. # Examples @@ -48,7 +48,7 @@ assert_eq!(d, e.as_()); let f: f64 = b.as_(); assert_eq!(b, f.as_()); ```" - }; + }; } #[cfg(feature = "nightly")] @@ -64,7 +64,7 @@ macro_rules! as_trait { } #[doc = as_trait_doc!()] - #[const_trait] + #[const_trait] pub trait As { #[doc = as_method_doc!()] fn as_(self) -> T @@ -131,7 +131,7 @@ macro_rules! primitive_cast_impl { from as Self } } - })* + })* }; } diff --git a/src/doc/checked.rs b/src/doc/checked.rs index f727f99..d4e85ae 100644 --- a/src/doc/checked.rs +++ b/src/doc/checked.rs @@ -37,7 +37,7 @@ doc::link_doc_comment!( macro_rules! checked_next_power_of_two { ($sign: ident $bits: literal) => { doc::doc_comment! { - #checked_next_power_of_two, + #checked_next_power_of_two, $sign $bits, "Returns the smallest power of two greater than or equal to `self`. If the next power of two is greater than `Self::MAX`, `None` is returned, otherwise the power of two is wrapped in `Some`.", diff --git a/src/doc/const_trait_fillers.rs b/src/doc/const_trait_fillers.rs index 0762267..5774bb6 100644 --- a/src/doc/const_trait_fillers.rs +++ b/src/doc/const_trait_fillers.rs @@ -1,7 +1,7 @@ macro_rules! impl_desc { - () => { - "The latest version of the nightly Rust compiler at the time `v0.7.0` was published (`v1.71.0-nightly`) unfortunately dropped support for the `const` implementation of common standard library traits such as `Add`, `BitOr`, etc. These methods below have therefore been provided to allow use of some of the methods these traits provided, in a const context." - }; + () => { + "The latest version of the nightly Rust compiler at the time `v0.7.0` was published (`v1.71.0-nightly`) unfortunately dropped support for the `const` implementation of common standard library traits such as `Add`, `BitOr`, etc. These methods below have therefore been provided to allow use of some of the methods these traits provided, in a const context." + }; } -pub(crate) use impl_desc; \ No newline at end of file +pub(crate) use impl_desc; diff --git a/src/doc/consts.rs b/src/doc/consts.rs index f749f90..319ab3c 100644 --- a/src/doc/consts.rs +++ b/src/doc/consts.rs @@ -85,9 +85,9 @@ macro_rules! bytes { pub(crate) use bytes; macro_rules! value_desc { - ($($lit: literal) +) => { - concat!("The value of `", $($lit,)+ "` represented by this type.") - } + ($($lit: literal) +) => { + concat!("The value of `", $($lit,)+ "` represented by this type.") + } } pub(crate) use value_desc; diff --git a/src/doc/mod.rs b/src/doc/mod.rs index 0df8280..333869d 100644 --- a/src/doc/mod.rs +++ b/src/doc/mod.rs @@ -11,9 +11,9 @@ pub mod unchecked; pub mod wrapping; macro_rules! arithmetic_doc { - ($Int: ty) => { + ($Int: ty) => { concat!("`", stringify!($Int), "` implements all the arithmetic traits from the [`core::ops`](https://doc.rust-lang.org/core/ops/) module. The behaviour of the implementation of these traits is the same as for Rust's primitive integers - i.e. in debug mode it panics on overflow, and in release mode it performs two's complement wrapping (see ). However, an attempt to divide by zero or calculate a remainder with a divisor of zero will always panic, unless the [`checked_`](#method.checked_div) methods are used, which never panic.") - } + } } pub(crate) use arithmetic_doc; @@ -96,31 +96,31 @@ macro_rules! doc_comment { { $(# $method: ident, )? $sign: ident $bits: literal, $($($desc: expr)+)? $(, $($code: expr)+)? } => { concat!( $($("\n\n", $desc), +,)? - $("\n\n", "See also: .", )? + $("\n\n", "See also: .", )? $( - doc::example_header!($sign $bits), - $($code), +, - "\n```" - )? + doc::example_header!($sign $bits), + $($code), +, + "\n```" + )? ) } } macro_rules! link_doc_comment { - ($($name: ident), *) => { - $( - macro_rules! $name { - ($sign: ident) => { - doc::doc_comment! { - #$name, - $sign 256, - } - }; - } - - pub(crate) use $name; - )* - } + ($($name: ident), *) => { + $( + macro_rules! $name { + ($sign: ident) => { + doc::doc_comment! { + #$name, + $sign 256, + } + }; + } + + pub(crate) use $name; + )* + } } pub(crate) use link_doc_comment; @@ -219,7 +219,7 @@ pub(crate) use trailing_ones; macro_rules! rotate_left { ($sign: ident $bits: literal, $u: literal) => { doc::doc_comment! { - #rotate_left, + #rotate_left, $sign $bits, "Shifts the bits to the left by a specified amount, `n`, wrapping the truncated bits to the end of the resulting integer." "Please note this isn't the same operation as the `<<` shifting operator!" @@ -232,7 +232,7 @@ pub(crate) use rotate_left; macro_rules! rotate_right { ($sign: ident $bits: literal, $u: literal) => { doc::doc_comment! { - #rotate_right, + #rotate_right, $sign $bits, "Shifts the bits to the left by a specified amount, `n`, wrapping the truncated bits to the end of the resulting integer." "Please note this isn't the same operation as the `>>` shifting operator!" @@ -246,12 +246,12 @@ pub(crate) use rotate_right; macro_rules! swap_bytes { ($sign: ident $bits: literal, $u: literal) => { doc::doc_comment! { - #swap_bytes, + #swap_bytes, $sign $bits, "Reverses the byte order of the integer.", "let n = " doc::type_str!($sign $bits) "::from(0x12345678901234567890123456789012" $u "128);\n" - "assert_eq!(n.swap_bytes().swap_bytes(), n);" + "assert_eq!(n.swap_bytes().swap_bytes(), n);" } } } @@ -261,12 +261,12 @@ pub(crate) use swap_bytes; macro_rules! reverse_bits { ($sign: ident $bits: literal, $u: literal) => { doc::doc_comment! { - #reverse_bits, + #reverse_bits, $sign $bits, "Reverses the order of bits in the integer. The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.", "let n = " doc::type_str!($sign $bits) "::from(0x12345678901234567890123456789012" $u "128);\n" - "assert_eq!(n.reverse_bits().reverse_bits(), n);" + "assert_eq!(n.reverse_bits().reverse_bits(), n);" } }; } @@ -291,7 +291,7 @@ pub(crate) use pow; macro_rules! next_power_of_two { ($sign: ident $bits: literal, $wrap: literal, $small: literal) => { doc::doc_comment! { - #next_power_of_two, + #next_power_of_two, $sign $bits, concat!("When return value overflows, it panics in debug mode and the return value is wrapped to ", $wrap, " in release mode (the only situation in which method can return ", $wrap, ")."), @@ -374,7 +374,7 @@ macro_rules! is_one { pub(crate) use is_one; crate::doc::link_doc_comment! { - unsigned_abs, + unsigned_abs, div_euclid, rem_euclid, ilog2, diff --git a/src/doc/overflowing.rs b/src/doc/overflowing.rs index f470936..6c90d46 100644 --- a/src/doc/overflowing.rs +++ b/src/doc/overflowing.rs @@ -1,7 +1,7 @@ macro_rules! impl_desc { - () => { - doc::arithmetic_impl_desc!("Overflowing", "overflowing", "Each method returns a tuple of type `(Self, bool)` where the first item of the tuple is the result of the calculation truncated to the number of bits of `self`, and the second item is a boolean which indicates whether overflow occurred (i.e. if the number of bits of the result of the calculation exceeded the number of bits of `self`).") - }; + () => { + doc::arithmetic_impl_desc!("Overflowing", "overflowing", "Each method returns a tuple of type `(Self, bool)` where the first item of the tuple is the result of the calculation truncated to the number of bits of `self`, and the second item is a boolean which indicates whether overflow occurred (i.e. if the number of bits of the result of the calculation exceeded the number of bits of `self`).") + }; } pub(crate) use impl_desc; diff --git a/src/doc/radix.rs b/src/doc/radix.rs index 1e8b0fb..c7a0613 100644 --- a/src/doc/radix.rs +++ b/src/doc/radix.rs @@ -11,8 +11,8 @@ macro_rules! impl_desc { pub(crate) use impl_desc; macro_rules! parse_str_radix { - ($ty: ty) => { - concat!( + ($ty: ty) => { + concat!( "This function works the same as `from_str_radix` except that it returns a `", stringify!($ty), "` instead of a `Result<", @@ -34,8 +34,8 @@ use bnum::types::U256; const DOESNT_COMPILE: U256 = U256::parse_str_radix(\"a13423\", 10); // Gives a compile error of \"error[E0080]: evaluation of constant value failed... the evaluated program panicked at 'attempt to parse integer from string containing invalid digit'\", ```" - ) - } + ) + } } -pub(crate) use parse_str_radix; \ No newline at end of file +pub(crate) use parse_str_radix; diff --git a/src/doc/saturating.rs b/src/doc/saturating.rs index 2c622f4..f16fc69 100644 --- a/src/doc/saturating.rs +++ b/src/doc/saturating.rs @@ -1,7 +1,7 @@ macro_rules! impl_desc { - () => { - doc::arithmetic_impl_desc!("Saturating", "saturating", "For each method, if overflow or underflow occurs, the largest or smallest value that can be represented by `Self` is returned instead.") - }; + () => { + doc::arithmetic_impl_desc!("Saturating", "saturating", "For each method, if overflow or underflow occurs, the largest or smallest value that can be represented by `Self` is returned instead.") + }; } pub(crate) use impl_desc; diff --git a/src/doc/unchecked.rs b/src/doc/unchecked.rs index 4fcfec6..0c10bd8 100644 --- a/src/doc/unchecked.rs +++ b/src/doc/unchecked.rs @@ -1,7 +1,7 @@ macro_rules! impl_desc { - () => { - doc::arithmetic_impl_desc!("Unchecked", "unchecked", "Each method results in undefined behavior if overflow/underflow occurs, i.e. when the checked equivalent would return `None`.") - }; + () => { + doc::arithmetic_impl_desc!("Unchecked", "unchecked", "Each method results in undefined behavior if overflow/underflow occurs, i.e. when the checked equivalent would return `None`.") + }; } pub(crate) use impl_desc; diff --git a/src/doc/wrapping.rs b/src/doc/wrapping.rs index 8e1d292..a44c2a8 100644 --- a/src/doc/wrapping.rs +++ b/src/doc/wrapping.rs @@ -1,7 +1,7 @@ macro_rules! impl_desc { - () => { - doc::arithmetic_impl_desc!("Wrapping", "wrapping", "Each method returns of the calculation truncated to the number of bits of `self`, i.e. they each return the first item in the tuple returned by their overflowing equivalent.") - }; + () => { + doc::arithmetic_impl_desc!("Wrapping", "wrapping", "Each method returns of the calculation truncated to the number of bits of `self`, i.e. they each return the first item in the tuple returned by their overflowing equivalent.") + }; } pub(crate) use impl_desc; @@ -27,7 +27,7 @@ crate::doc::link_doc_comment!( macro_rules! wrapping_next_power_of_two { ($sign: ident $bits: literal) => { doc::doc_comment! { - #wrapping_next_power_of_two, + #wrapping_next_power_of_two, $sign $bits, concat!("Returns the smallest power of two greater than or equal to `self`. If the next power of two is greater than `Self::MAX`, the return value is wrapped to `Self::MIN`."), diff --git a/src/errors/macros.rs b/src/errors/macros.rs index d573841..f6eac34 100644 --- a/src/errors/macros.rs +++ b/src/errors/macros.rs @@ -51,4 +51,4 @@ macro_rules! result_expect { } }; } -pub(crate) use result_expect; \ No newline at end of file +pub(crate) use result_expect; diff --git a/src/errors/tryfrom.rs b/src/errors/tryfrom.rs index d278d1a..8913182 100644 --- a/src/errors/tryfrom.rs +++ b/src/errors/tryfrom.rs @@ -6,11 +6,14 @@ use core::fmt::{self, Display, Formatter}; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct TryFromIntError(pub(crate) ()); -const ERROR_MESSAGE: &str = concat!(super::err_prefix!(), "out of range integral type conversion attempted"); +const ERROR_MESSAGE: &str = concat!( + super::err_prefix!(), + "out of range integral type conversion attempted" +); impl Display for TryFromIntError { #[inline] fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}", ERROR_MESSAGE) } -} \ No newline at end of file +} diff --git a/src/float/classify.rs b/src/float/classify.rs index 526390c..4f3cfb8 100644 --- a/src/float/classify.rs +++ b/src/float/classify.rs @@ -22,24 +22,24 @@ impl Float { self.to_int().is_negative() } - crate::nightly::const_fns! { - #[inline] - pub const fn is_finite(self) -> bool { - self.to_bits() & Masks::::FINITE_MASK != Masks::::FINITE_MASK - } - - #[inline] - pub const fn is_infinite(self) -> bool { - self.abs().to_bits() == Masks::::FINITE_MASK - /*let bits = self.abs().to_bits(); - bits.trailing_zeros() == Self::MB && bits.count_ones() == Self::EXPONENT_BITS as ExpType*/ - } - - /*#[inline] - pub const fn is_quiet_indefinite_nan(self) -> bool { - self == Self::NAN - }*/ - } + crate::nightly::const_fns! { + #[inline] + pub const fn is_finite(self) -> bool { + self.to_bits() & Masks::::FINITE_MASK != Masks::::FINITE_MASK + } + + #[inline] + pub const fn is_infinite(self) -> bool { + self.abs().to_bits() == Masks::::FINITE_MASK + /*let bits = self.abs().to_bits(); + bits.trailing_zeros() == Self::MB && bits.count_ones() == Self::EXPONENT_BITS as ExpType*/ + } + + /*#[inline] + pub const fn is_quiet_indefinite_nan(self) -> bool { + self == Self::NAN + }*/ + } #[inline] pub const fn is_nan(self) -> bool { @@ -47,17 +47,17 @@ impl Float { !self.is_finite() && self.to_bits().trailing_zeros() < Self::MB } - crate::nightly::const_fns! { - /*#[inline] - pub const fn is_quiet_nan(self) -> bool { - self.to_bits() & Masks::::Q_NAN_MASK == Masks::::Q_NAN_MASK - } + crate::nightly::const_fns! { + /*#[inline] + pub const fn is_quiet_nan(self) -> bool { + self.to_bits() & Masks::::Q_NAN_MASK == Masks::::Q_NAN_MASK + } - #[inline] - pub const fn is_signalling_nan(self) -> bool { - self.to_bits() & Masks::::Q_NAN_MASK == Self::INFINITY.to_bits() - }*/ - } + #[inline] + pub const fn is_signalling_nan(self) -> bool { + self.to_bits() & Masks::::Q_NAN_MASK == Self::INFINITY.to_bits() + }*/ + } #[inline] pub const fn is_subnormal(self) -> bool { @@ -84,32 +84,32 @@ impl Float { last.trailing_zeros() >= Digit::BITS - 1 } - crate::nightly::const_fn! { - #[inline] - pub const fn classify(self) -> FpCategory { - let u = self.abs().to_bits(); - if u.is_zero() { - FpCategory::Zero - } else if u == Self::INFINITY.to_bits() { - FpCategory::Infinite - } else { - let u = u & Masks::::FINITE_MASK; - if u.is_zero() { - FpCategory::Subnormal - } else if u == Masks::::FINITE_MASK { - FpCategory::Nan - } else { - FpCategory::Normal - } - } - } - } + crate::nightly::const_fn! { + #[inline] + pub const fn classify(self) -> FpCategory { + let u = self.abs().to_bits(); + if u.is_zero() { + FpCategory::Zero + } else if u == Self::INFINITY.to_bits() { + FpCategory::Infinite + } else { + let u = u & Masks::::FINITE_MASK; + if u.is_zero() { + FpCategory::Subnormal + } else if u == Masks::::FINITE_MASK { + FpCategory::Nan + } else { + FpCategory::Normal + } + } + } + } } #[cfg(test)] mod tests { use crate::test::types::{ftest, FTEST}; - use crate::test::test_bignum; + use crate::test::test_bignum; test_bignum! { function: ::is_sign_positive(a: ftest) @@ -135,7 +135,7 @@ mod tests { test_bignum! { function: ::classify(a: ftest) } - + #[test] fn is_zero() { let z1 = FTEST::ZERO; diff --git a/src/float/cmp.rs b/src/float/cmp.rs index dc12448..62f01b3 100644 --- a/src/float/cmp.rs +++ b/src/float/cmp.rs @@ -3,29 +3,29 @@ use crate::{BIntD8, BUintD8}; use core::cmp::{PartialOrd, PartialEq, Ordering}; impl Float { - crate::nightly::const_fns! { - #[inline] - pub const fn max(self, other: Self) -> Self { - handle_nan!(other; self); - handle_nan!(self; other); - if let Ordering::Less = self.total_cmp(&other) { - other - } else { - self - } - } + crate::nightly::const_fns! { + #[inline] + pub const fn max(self, other: Self) -> Self { + handle_nan!(other; self); + handle_nan!(self; other); + if let Ordering::Less = self.total_cmp(&other) { + other + } else { + self + } + } - #[inline] - pub const fn min(self, other: Self) -> Self { - handle_nan!(other; self); - handle_nan!(self; other); - if let Ordering::Greater = self.total_cmp(&other) { - other - } else { - self - } - } - } + #[inline] + pub const fn min(self, other: Self) -> Self { + handle_nan!(other; self); + handle_nan!(self; other); + if let Ordering::Greater = self.total_cmp(&other) { + other + } else { + self + } + } + } #[inline] pub const fn maximum(self, other: Self) -> Self { @@ -49,20 +49,20 @@ impl Float { } } - crate::nightly::const_fns! { - #[inline] - pub const fn clamp(self, min: Self, max: Self) -> Self { - assert!(min <= max); - let mut x = self; - if x < min { - x = min; - } - if x > max { - x = max; - } - x - } - } + crate::nightly::const_fns! { + #[inline] + pub const fn clamp(self, min: Self, max: Self) -> Self { + assert!(min <= max); + let mut x = self; + if x < min { + x = min; + } + if x > max { + x = max; + } + x + } + } #[inline] pub const fn total_cmp(&self, other: &Self) -> Ordering { @@ -77,48 +77,48 @@ impl Float { } crate::nightly::impl_const! { - impl const PartialEq for Float { - #[inline] - fn eq(&self, other: &Self) -> bool { - handle_nan!(false; self, other); - (self.is_zero() && other.is_zero()) || BUintD8::eq(&self.to_bits(), &other.to_bits()) - } - } + impl const PartialEq for Float { + #[inline] + fn eq(&self, other: &Self) -> bool { + handle_nan!(false; self, other); + (self.is_zero() && other.is_zero()) || BUintD8::eq(&self.to_bits(), &other.to_bits()) + } + } } crate::nightly::impl_const! { - impl const PartialOrd for Float { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - handle_nan!(None; self, other); - if self.is_zero() && other.is_zero() { - return Some(Ordering::Equal); - } - Some(self.total_cmp(other)) - } - } + impl const PartialOrd for Float { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + handle_nan!(None; self, other); + if self.is_zero() && other.is_zero() { + return Some(Ordering::Equal); + } + Some(self.total_cmp(other)) + } + } } #[cfg(test)] mod tests { - use crate::test::test_bignum; - use crate::test::types::{ftest, FTEST}; + use crate::test::test_bignum; + use crate::test::types::{ftest, FTEST}; test_bignum! { function: ::max(a: ftest, b: ftest), - cases: [(0.0, -0.0), (-0.0, 0.0)] + cases: [(0.0, -0.0), (-0.0, 0.0)] } test_bignum! { function: ::min(a: ftest, b: ftest), - cases: [(0.0, -0.0), (-0.0, 0.0)] + cases: [(0.0, -0.0), (-0.0, 0.0)] } test_bignum! { function: ::maximum(a: ftest, b: ftest), - cases: [(0.0, -0.0), (-0.0, 0.0)] + cases: [(0.0, -0.0), (-0.0, 0.0)] } test_bignum! { function: ::minimum(a: ftest, b: ftest), - cases: [(0.0, -0.0), (-0.0, 0.0)] + cases: [(0.0, -0.0), (-0.0, 0.0)] } test_bignum! { function: ::clamp(a: ftest, b: ftest, c: ftest), diff --git a/src/float/consts.rs b/src/float/consts.rs index 29c9fd2..9dd548e 100644 --- a/src/float/consts.rs +++ b/src/float/consts.rs @@ -108,60 +108,60 @@ impl Float { #[cfg(test)] mod tests { use super::super::{F64, F32}; - use crate::test::TestConvert; - use crate::test::types::{ftest, FTEST}; - use crate::ExpType; + use crate::test::TestConvert; + use crate::test::types::{ftest, FTEST}; + use crate::ExpType; macro_rules! test_constant { ($big: ident :: $constant: ident == $primitive: expr) => { - paste::paste! { - #[test] - fn []() { - assert_eq!(TestConvert::into($big::$constant), TestConvert::into($primitive), "constant `{}` not equal to the primitive equivalent", stringify!($constant)); - } - } + paste::paste! { + #[test] + fn []() { + assert_eq!(TestConvert::into($big::$constant), TestConvert::into($primitive), "constant `{}` not equal to the primitive equivalent", stringify!($constant)); + } + } } } - macro_rules! test_constants { - {$($constant: ident), *} => { + macro_rules! test_constants { + {$($constant: ident), *} => { $( - test_constant!(FTEST::$constant == ftest::$constant); - )* - }; - } - - macro_rules! test_numeric_constants { - [$(($constant: ident, $value: expr)), *] => { - $( - paste::paste! { - test_constant!(FTEST::$constant == $value as ftest); - } - )* - }; - } - - test_constants! { - /*NAN, */INFINITY, NEG_INFINITY, MAX, MIN, MIN_POSITIVE, EPSILON, MIN_EXP, MAX_EXP, RADIX, MANTISSA_DIGITS, DIGITS - } - // don't test NAN as Rust f64/f32 NAN bit pattern not guaranteed to be stable across version - - #[test] - fn nan_consts_is_nan() { - assert!(FTEST::NAN.is_nan()); - assert!(FTEST::QNAN.is_nan()); - } - - test_numeric_constants![ - (ZERO, 0.0), (NEG_ZERO, -0.0), (ONE, 1.0), (QUARTER, 0.25), (HALF, 0.5), (NEG_ONE, -1) - ]; - - test_constant!(F64::BITS == 64 as ExpType); - test_constant!(F32::BITS == 32 as ExpType); - test_constant!(F64::EXPONENT_BITS == 11 as ExpType); - test_constant!(F32::EXPONENT_BITS == 8 as ExpType); - test_constant!(F64::EXP_BIAS == 1023i64); - test_constant!(F32::EXP_BIAS == 127i32); - test_constant!(F64::MAX_UNBIASED_EXP == 2046u64); - test_constant!(F32::MAX_UNBIASED_EXP == 254u32); + test_constant!(FTEST::$constant == ftest::$constant); + )* + }; + } + + macro_rules! test_numeric_constants { + [$(($constant: ident, $value: expr)), *] => { + $( + paste::paste! { + test_constant!(FTEST::$constant == $value as ftest); + } + )* + }; + } + + test_constants! { + /*NAN, */INFINITY, NEG_INFINITY, MAX, MIN, MIN_POSITIVE, EPSILON, MIN_EXP, MAX_EXP, RADIX, MANTISSA_DIGITS, DIGITS + } + // don't test NAN as Rust f64/f32 NAN bit pattern not guaranteed to be stable across version + + #[test] + fn nan_consts_is_nan() { + assert!(FTEST::NAN.is_nan()); + assert!(FTEST::QNAN.is_nan()); + } + + test_numeric_constants![ + (ZERO, 0.0), (NEG_ZERO, -0.0), (ONE, 1.0), (QUARTER, 0.25), (HALF, 0.5), (NEG_ONE, -1) + ]; + + test_constant!(F64::BITS == 64 as ExpType); + test_constant!(F32::BITS == 32 as ExpType); + test_constant!(F64::EXPONENT_BITS == 11 as ExpType); + test_constant!(F32::EXPONENT_BITS == 8 as ExpType); + test_constant!(F64::EXP_BIAS == 1023i64); + test_constant!(F32::EXP_BIAS == 127i32); + test_constant!(F64::MAX_UNBIASED_EXP == 2046u64); + test_constant!(F32::MAX_UNBIASED_EXP == 254u32); } \ No newline at end of file diff --git a/src/float/convert.rs b/src/float/convert.rs index 8b9b417..e166b74 100644 --- a/src/float/convert.rs +++ b/src/float/convert.rs @@ -17,9 +17,9 @@ impl Float { #[cfg(test)] mod tests { - use crate::test::test_bignum; + use crate::test::test_bignum; use crate::test::types::{ftest, FTEST}; - use super::super::{F64, F32}; + use super::super::{F64, F32}; test_bignum! { function: ::to_bits(a: ftest) diff --git a/src/float/endian.rs b/src/float/endian.rs index 744beb6..33637b0 100644 --- a/src/float/endian.rs +++ b/src/float/endian.rs @@ -3,37 +3,37 @@ use crate::BUintD8; use crate::digit::u8 as digit; impl Float { - #[cfg(feature = "nightly")] + #[cfg(feature = "nightly")] #[inline] pub const fn to_be_bytes(self) -> [u8; W * digit::BYTES as usize] { self.to_bits().to_be_bytes() } - #[cfg(feature = "nightly")] + #[cfg(feature = "nightly")] #[inline] pub const fn to_le_bytes(self) -> [u8; W * digit::BYTES as usize] { self.to_bits().to_le_bytes() } - #[cfg(feature = "nightly")] + #[cfg(feature = "nightly")] #[inline] pub const fn to_ne_bytes(self) -> [u8; W * digit::BYTES as usize] { self.to_bits().to_ne_bytes() } - #[cfg(feature = "nightly")] + #[cfg(feature = "nightly")] #[inline] pub const fn from_be_bytes(bytes: [u8; W * digit::BYTES as usize]) -> Self { Self::from_bits(BUintD8::from_be_bytes(bytes)) } - #[cfg(feature = "nightly")] + #[cfg(feature = "nightly")] #[inline] pub const fn from_le_bytes(bytes: [u8; W * digit::BYTES as usize]) -> Self { Self::from_bits(BUintD8::from_le_bytes(bytes)) } - #[cfg(feature = "nightly")] + #[cfg(feature = "nightly")] #[inline] pub const fn from_ne_bytes(bytes: [u8; W * digit::BYTES as usize]) -> Self { Self::from_bits(BUintD8::from_ne_bytes(bytes)) @@ -44,7 +44,7 @@ impl Float { #[cfg(test)] mod tests { use crate::test::U8ArrayWrapper; - use crate::test::test_bignum; + use crate::test::test_bignum; use crate::test::types::{ftest, FTEST}; test_bignum! { diff --git a/src/float/math.rs b/src/float/math.rs index 53da46e..702dc51 100644 --- a/src/float/math.rs +++ b/src/float/math.rs @@ -197,16 +197,16 @@ mul_add, div_euclid, rem_euclid, powi, powf, exp, exp2, ln, log, log2, log10, cb */ impl Float { - crate::nightly::const_fns! { - #[inline] - pub const fn abs(self) -> Self { - if self.is_sign_negative() { - -self - } else { - self - } - } - } + crate::nightly::const_fns! { + #[inline] + pub const fn abs(self) -> Self { + if self.is_sign_negative() { + -self + } else { + self + } + } + } pub fn sqrt(self) -> Self { handle_nan!(self; self); @@ -218,7 +218,7 @@ impl Float { return Self::INFINITY; } if self.is_sign_negative() { - return Self::NAN; + return Self::NAN; /*let u = BUintD8::MAX << (Self::MB - 1); return Self::from_bits(u);*/ } @@ -306,9 +306,9 @@ impl Float { } u &= !m; } else if self.is_sign_negative() { - return Self::NEG_ZERO; - } else if !(u << 1u8).is_zero() { - return Self::ONE; + return Self::NEG_ZERO; + } else if !(u << 1u8).is_zero() { + return Self::ONE; } Self::from_bits(u) } @@ -331,10 +331,10 @@ impl Float { } bits &= !m; } else if self.is_sign_positive() { - return Self::ZERO; - } else if !(bits << 1u8).is_zero() { - return Self::NEG_ONE; - } + return Self::ZERO; + } else if !(bits << 1u8).is_zero() { + return Self::NEG_ONE; + } Self::from_bits(bits) } @@ -367,9 +367,9 @@ impl Float { #[inline] pub fn fract_trunc(self) -> (Self, Self) { handle_nan!((self, self); self); - if self.is_infinite() { - return (Self::NAN, self); - } + if self.is_infinite() { + return (Self::NAN, self); + } let mut u = self.to_bits(); let e = self.exponent() - Self::EXP_BIAS; @@ -430,26 +430,26 @@ impl Float { } } - #[inline] - pub fn powi(mut self, n: i32) -> Self where [(); W * 2]:, { - if n == 0 { - return Self::ONE; - } - let mut n_abs = n.abs(); - let mut x = Self::ONE; - while n_abs != 0 { - if n_abs & 1 == 1 { - x = x * self; - } - self = self * self; - n_abs >>= 1; - } - if n.is_negative() { - Self::ONE / (self * x) - } else { - self * x - } - } + #[inline] + pub fn powi(mut self, n: i32) -> Self where [(); W * 2]:, { + if n == 0 { + return Self::ONE; + } + let mut n_abs = n.abs(); + let mut x = Self::ONE; + while n_abs != 0 { + if n_abs & 1 == 1 { + x = x * self; + } + self = self * self; + n_abs >>= 1; + } + if n.is_negative() { + Self::ONE / (self * x) + } else { + self * x + } + } /*pub fn remquof(mut self, mut y: Self) -> /*(Self, BIntD8)*/(Self, Self) { handle_nan!(self; self); @@ -553,95 +553,95 @@ impl Float { } }*/ - #[cfg(test)] - pub(crate) fn to_f64(self) -> f64 { - f64::from_bits(self.to_bits().as_()) - } + #[cfg(test)] + pub(crate) fn to_f64(self) -> f64 { + f64::from_bits(self.to_bits().as_()) + } - #[cfg(test)] - pub(crate) fn to_f32(self) -> f32 { - f32::from_bits(self.to_bits().as_()) - } + #[cfg(test)] + pub(crate) fn to_f32(self) -> f32 { + f32::from_bits(self.to_bits().as_()) + } } #[cfg(test)] impl super::F32 { - #[inline] - pub fn recip(self) -> Self { - /*let (e, m) = self.exp_mant(); - let normalised = Self::from_exp_mant(self.is_sign_negative(), Self::EXP_BIAS.to_bits() - BUintD8::ONE, m); - println!("norm: {}", normalised.to_f64()); - let r = normalised.recip_internal(); - let e = self.exponent() - Self::EXP_BIAS; - //println!("{}", e); - let e = (-e) + Self::EXP_BIAS; - Self::from_exp_mant(self.is_sign_negative(), e.to_bits() - BUintD8::ONE, r.exp_mant().1)*/ - self.recip_internal() - } - - #[inline] - pub fn recip_internal(self) -> Self { - if self.is_zero() { - return Self::NAN; - } - // solve 1/b - x = 0 so 1/x - b = 0 =: f(x) - // x_{n + 1} = x_n - f(x_n) / f'(x_n) - // = x_n - (1/x_n - b) / (-1/x_n^2) - // = x_n + (x_n - b x_n^2) - // = x_n (2 - b x_n) - let (e, m) = self.exp_mant(); - let e = BIntD8::from_bits(e) - Self::EXP_BIAS; - let inv_e = (-e + Self::EXP_BIAS).to_bits() - BUintD8::ONE; - //println!("{}", e); - let normalised = Self::from_exp_mant(false, Self::EXP_BIAS.to_bits() - BUintD8::ONE, m); - if normalised == Self::ONE { - return Self::from_exp_mant(self.is_sign_negative(), inv_e + 1, BUintD8::ZERO); - } - //println!("norm init: {:064b}", normalised.to_bits()); - let mut x_n = Self::from_bits((normalised * Self::HALF).to_bits() ^ (BUintD8::MAX >> (Self::BITS - Self::MB))); - - let mut m_n = x_n.exp_mant().1 << 1; - - /* - 0.5 <= x_n < 1 - 1 <= normalised < 2 - so 0.5 <= x_n * normalised < 2 - 1 <= x_n * 2 < 2 - */ - - //println!("x_n: {}", x_n.to_f32()); - let mut iters = 0; - loop { - let a1 = x_n * Self::TWO; - let a2 = x_n * normalised * x_n; - let x_n_1 = a1 - a2; - assert!(a1.to_f32() >= 1.0 && a1.to_f32() <= 2.0); - assert!(a2.to_f32() >= 0.5 && a2.to_f32() <= 1.0); - - let ma1 = m_n << 1; - let xnf = x_n_1.to_f32(); - assert!(0.5 <= xnf && xnf < 1.0, "{}, norm: {}", xnf, normalised.to_f32()); - // x_n * (2 - norm * x_n) - if x_n_1 == x_n || iters == 100 { - //println!("done: new: {}, old: {}", x_n_1.to_f64(), x_n.to_f64()); - //println!("norm: {:064b}", x_n_1.to_bits()); - let mut m = x_n_1.exp_mant().1; - if m.bit(Self::MB) { - m ^= BUintD8::ONE << Self::MB; - } - let unnormalised = Self::from_exp_mant(self.is_sign_negative(), inv_e, m); - println!("iters: {}", iters); - return unnormalised; - } - x_n = x_n_1; - iters += 1; - } - } + #[inline] + pub fn recip(self) -> Self { + /*let (e, m) = self.exp_mant(); + let normalised = Self::from_exp_mant(self.is_sign_negative(), Self::EXP_BIAS.to_bits() - BUintD8::ONE, m); + println!("norm: {}", normalised.to_f64()); + let r = normalised.recip_internal(); + let e = self.exponent() - Self::EXP_BIAS; + //println!("{}", e); + let e = (-e) + Self::EXP_BIAS; + Self::from_exp_mant(self.is_sign_negative(), e.to_bits() - BUintD8::ONE, r.exp_mant().1)*/ + self.recip_internal() + } + + #[inline] + pub fn recip_internal(self) -> Self { + if self.is_zero() { + return Self::NAN; + } + // solve 1/b - x = 0 so 1/x - b = 0 =: f(x) + // x_{n + 1} = x_n - f(x_n) / f'(x_n) + // = x_n - (1/x_n - b) / (-1/x_n^2) + // = x_n + (x_n - b x_n^2) + // = x_n (2 - b x_n) + let (e, m) = self.exp_mant(); + let e = BIntD8::from_bits(e) - Self::EXP_BIAS; + let inv_e = (-e + Self::EXP_BIAS).to_bits() - BUintD8::ONE; + //println!("{}", e); + let normalised = Self::from_exp_mant(false, Self::EXP_BIAS.to_bits() - BUintD8::ONE, m); + if normalised == Self::ONE { + return Self::from_exp_mant(self.is_sign_negative(), inv_e + 1, BUintD8::ZERO); + } + //println!("norm init: {:064b}", normalised.to_bits()); + let mut x_n = Self::from_bits((normalised * Self::HALF).to_bits() ^ (BUintD8::MAX >> (Self::BITS - Self::MB))); + + let mut m_n = x_n.exp_mant().1 << 1; + + /* + 0.5 <= x_n < 1 + 1 <= normalised < 2 + so 0.5 <= x_n * normalised < 2 + 1 <= x_n * 2 < 2 + */ + + //println!("x_n: {}", x_n.to_f32()); + let mut iters = 0; + loop { + let a1 = x_n * Self::TWO; + let a2 = x_n * normalised * x_n; + let x_n_1 = a1 - a2; + assert!(a1.to_f32() >= 1.0 && a1.to_f32() <= 2.0); + assert!(a2.to_f32() >= 0.5 && a2.to_f32() <= 1.0); + + let ma1 = m_n << 1; + let xnf = x_n_1.to_f32(); + assert!(0.5 <= xnf && xnf < 1.0, "{}, norm: {}", xnf, normalised.to_f32()); + // x_n * (2 - norm * x_n) + if x_n_1 == x_n || iters == 100 { + //println!("done: new: {}, old: {}", x_n_1.to_f64(), x_n.to_f64()); + //println!("norm: {:064b}", x_n_1.to_bits()); + let mut m = x_n_1.exp_mant().1; + if m.bit(Self::MB) { + m ^= BUintD8::ONE << Self::MB; + } + let unnormalised = Self::from_exp_mant(self.is_sign_negative(), inv_e, m); + println!("iters: {}", iters); + return unnormalised; + } + x_n = x_n_1; + iters += 1; + } + } } #[cfg(test)] mod tests { - use crate::test::test_bignum; + use crate::test::test_bignum; use crate::test::types::{ftest, FTEST}; test_bignum! { @@ -680,13 +680,13 @@ mod tests { function: ::rem_euclid(f1: ftest, f2: ftest) } - test_bignum! { - function: ::powi(f: ftest, n: i32) - } + test_bignum! { + function: ::powi(f: ftest, n: i32) + } #[test] fn fmod() { - use super::super::F64; + use super::super::F64; let f1 = 0.0; let f2 = f64::INFINITY; //println!("{:064b}", ((-0.0f64).div_euclid(f2)).to_bits()); @@ -697,64 +697,64 @@ mod tests { assert!(a == b.into()); } - quickcheck::quickcheck! { - fn qc_recip(u: u32) -> quickcheck::TestResult { - let f = f32::from_bits(u); - if !f.is_finite() || f >= 2.0 || f <= 1.0 { - return quickcheck::TestResult::discard(); - } - - let b1 = f.recip().to_bits(); - let b2 = super::super::F32::from(f).recip().to_f32().to_bits(); - return quickcheck::TestResult::from_bool(b1 == b2 || b1 + 1 == b2); - } - } - - #[test] - fn recip2() { - assert!((0.0 as ftest).to_bits().count_zeros() == 32); - use super::super::F32; - - let f1 = 1.7517333f32; //f32::from_bits(0b0_01111110_01001000000000000000000u32); - println!("{}", f1); - - println!("{:032b}", f1.recip().to_bits()); - println!("{:032b}", F32::from(f1).recip_internal().to_f32().to_bits()); - panic!("") - } - - test_bignum! { - function: ::recip(f: ftest), - skip: !f.is_finite() || f == 0.0 || f >= 2.0 || f <= 1.0 - } - - #[test] - fn recip_u8() { - let mut g = true; - let mut close = true; - for i in 1..=u8::MAX { - let u = 0b0_01111110_00000000000000000000000u32 | ((i as u32) << 15); - let f = f32::from_bits(u); - - let b1 = f.recip().to_bits(); - let b2 = super::super::F32::from(f).recip_internal().to_f32().to_bits(); - let eq = b1 == b2; - if !eq { - println!("{:08b}", i); - if b2 - b1 != 1 { - close = false; - } - } - if b1 > b2 { - if b1 > b2 { - g = false; - } - } - } - println!("all greater: {}", g); - println!("all close: {}", close); - panic!("") - } + quickcheck::quickcheck! { + fn qc_recip(u: u32) -> quickcheck::TestResult { + let f = f32::from_bits(u); + if !f.is_finite() || f >= 2.0 || f <= 1.0 { + return quickcheck::TestResult::discard(); + } + + let b1 = f.recip().to_bits(); + let b2 = super::super::F32::from(f).recip().to_f32().to_bits(); + return quickcheck::TestResult::from_bool(b1 == b2 || b1 + 1 == b2); + } + } + + #[test] + fn recip2() { + assert!((0.0 as ftest).to_bits().count_zeros() == 32); + use super::super::F32; + + let f1 = 1.7517333f32; //f32::from_bits(0b0_01111110_01001000000000000000000u32); + println!("{}", f1); + + println!("{:032b}", f1.recip().to_bits()); + println!("{:032b}", F32::from(f1).recip_internal().to_f32().to_bits()); + panic!("") + } + + test_bignum! { + function: ::recip(f: ftest), + skip: !f.is_finite() || f == 0.0 || f >= 2.0 || f <= 1.0 + } + + #[test] + fn recip_u8() { + let mut g = true; + let mut close = true; + for i in 1..=u8::MAX { + let u = 0b0_01111110_00000000000000000000000u32 | ((i as u32) << 15); + let f = f32::from_bits(u); + + let b1 = f.recip().to_bits(); + let b2 = super::super::F32::from(f).recip_internal().to_f32().to_bits(); + let eq = b1 == b2; + if !eq { + println!("{:08b}", i); + if b2 - b1 != 1 { + close = false; + } + } + if b1 > b2 { + if b1 > b2 { + g = false; + } + } + } + println!("all greater: {}", g); + println!("all close: {}", close); + panic!("") + } } //0011111111101001100110011001100110011001100111110001100011111001 //0011111111100000000000000000000000000000000000110110111110011100 diff --git a/src/float/mod.rs b/src/float/mod.rs index ce1c44f..25be102 100644 --- a/src/float/mod.rs +++ b/src/float/mod.rs @@ -116,45 +116,45 @@ impl Float { Self::ONE.copysign(self) } - #[inline] - pub const fn next_up(self) -> Self { - use core::num::FpCategory; - - match self.classify() { - FpCategory::Nan => self, - FpCategory::Infinite => if self.is_sign_negative() { - Self::MIN - } else { - self - }, - FpCategory::Zero => Self::MIN_POSITIVE_SUBNORMAL, - _ => if self.is_sign_negative() { - Self::from_bits(self.to_bits() - BUintD8::ONE) - } else { - Self::from_bits(self.to_bits() + BUintD8::ONE) - }, - } - } - - #[inline] - pub const fn next_down(self) -> Self { - use core::num::FpCategory; - - match self.classify() { - FpCategory::Nan => self, - FpCategory::Infinite => if self.is_sign_negative() { - self - } else { - Self::MAX - }, - FpCategory::Zero => Self::MAX_NEGATIVE_SUBNORMAL, - _ => if self.is_sign_negative() { - Self::from_bits(self.to_bits() + BUintD8::ONE) - } else { - Self::from_bits(self.to_bits() - BUintD8::ONE) - } - } - } + #[inline] + pub const fn next_up(self) -> Self { + use core::num::FpCategory; + + match self.classify() { + FpCategory::Nan => self, + FpCategory::Infinite => if self.is_sign_negative() { + Self::MIN + } else { + self + }, + FpCategory::Zero => Self::MIN_POSITIVE_SUBNORMAL, + _ => if self.is_sign_negative() { + Self::from_bits(self.to_bits() - BUintD8::ONE) + } else { + Self::from_bits(self.to_bits() + BUintD8::ONE) + }, + } + } + + #[inline] + pub const fn next_down(self) -> Self { + use core::num::FpCategory; + + match self.classify() { + FpCategory::Nan => self, + FpCategory::Infinite => if self.is_sign_negative() { + self + } else { + Self::MAX + }, + FpCategory::Zero => Self::MAX_NEGATIVE_SUBNORMAL, + _ => if self.is_sign_negative() { + Self::from_bits(self.to_bits() + BUintD8::ONE) + } else { + Self::from_bits(self.to_bits() - BUintD8::ONE) + } + } + } } impl Default for Float { @@ -220,8 +220,8 @@ impl From for F32 { #[cfg(test)] mod tests { - use crate::test::test_bignum; - use crate::test::types::{ftest, FTEST}; + use crate::test::test_bignum; + use crate::test::types::{ftest, FTEST}; test_bignum! { function: ::copysign(f1: ftest, f2: ftest) @@ -232,10 +232,10 @@ mod tests { } test_bignum! { - function: ::next_up(f: ftest) - } + function: ::next_up(f: ftest) + } test_bignum! { - function: ::next_down(f: ftest) - } + function: ::next_down(f: ftest) + } } \ No newline at end of file diff --git a/src/float/ops.rs b/src/float/ops.rs index f702f17..c5636bb 100644 --- a/src/float/ops.rs +++ b/src/float/ops.rs @@ -69,10 +69,10 @@ impl Float { } if a_exp > Self::MAX_UNBIASED_EXP { return if negative { - Self::NEG_INFINITY - } else { - Self::INFINITY - }; + Self::NEG_INFINITY + } else { + Self::INFINITY + }; } mant >>= 2 as ExpType; @@ -82,8 +82,8 @@ impl Float { } else { mant ^= BUintD8::ONE << Self::MB; } - let a = Self::from_exp_mant(negative, a_exp, mant); - a + let a = Self::from_exp_mant(negative, a_exp, mant); + a } } @@ -97,13 +97,13 @@ impl Add for Float { let a = match (self.classify(), rhs.classify()) { (FpCategory::Nan, _) => self, (_, FpCategory::Nan) => rhs, - (FpCategory::Infinite, FpCategory::Infinite) => { - if self_negative ^ rhs_negative { - Self::NAN - } else { - self - } - } + (FpCategory::Infinite, FpCategory::Infinite) => { + if self_negative ^ rhs_negative { + Self::NAN + } else { + self + } + } (FpCategory::Infinite, _) => self, (_, FpCategory::Infinite) => rhs, (FpCategory::Zero, FpCategory::Zero) => if self_negative && rhs_negative { @@ -120,8 +120,8 @@ impl Add for Float { } } }; - //assert_eq!(a.to_bits(), (self.to_f64() + rhs.to_f64()).to_bits().into()); - a + //assert_eq!(a.to_bits(), (self.to_f64() + rhs.to_f64()).to_bits().into()); + a } } @@ -249,15 +249,15 @@ impl Sub for Float { #[inline] fn sub(self, rhs: Self) -> Self { - //println!("{:064b} {:064b}", self.to_bits(), rhs.to_bits()); + //println!("{:064b} {:064b}", self.to_bits(), rhs.to_bits()); match (self.classify(), rhs.classify()) { (FpCategory::Nan, _) => self, (_, FpCategory::Nan) => rhs, (FpCategory::Infinite, FpCategory::Infinite) => match (self.is_sign_negative(), rhs.is_sign_negative()) { - (true, false) => Self::NEG_INFINITY, - (false, true) => Self::INFINITY, - _ => Self::NAN, - }, + (true, false) => Self::NEG_INFINITY, + (false, true) => Self::INFINITY, + _ => Self::NAN, + }, (FpCategory::Infinite, _) => self, (_, FpCategory::Infinite) => rhs.neg(), (_, _) => { @@ -352,10 +352,10 @@ impl Float { let mut mant_prod = mant_a.widening_mul(mant_b); let prod_bits = if mant_prod.1.bits() == 0 { - mant_prod.0.bits() - } else { - mant_prod.1.bits() + Self::BITS - }; + mant_prod.0.bits() + } else { + mant_prod.1.bits() + Self::BITS + }; if prod_bits == 0 { return if negative { @@ -389,63 +389,63 @@ impl Float { } let total_shift = BUintD8::from(extra_bits) + extra_shift; - let mp0tz = mant_prod.0.trailing_zeros(); - let tz = if mp0tz == Self::BITS { - mant_prod.1.trailing_zeros() + Self::BITS - } else { - mp0tz - }; + let mp0tz = mant_prod.0.trailing_zeros(); + let tz = if mp0tz == Self::BITS { + mant_prod.1.trailing_zeros() + Self::BITS + } else { + mp0tz + }; let sticky_bit = BUintD8::from(tz + 1) < total_shift; let mut mant = match (total_shift - BUintD8::ONE).to_exp_type() { Some(sub) => if sub > Self::BITS * 2 { - (BUintD8::ZERO, BUintD8::ZERO) - } else if sub >= Self::BITS { - (mant_prod.1 >> (sub - Self::BITS), BUintD8::ZERO) - } else { - let mask = BUintD8::MAX >> (Self::BITS - sub); - let carry = mant_prod.1 & mask; - mant_prod.1 >>= sub; - mant_prod.0 = (mant_prod.0 >> sub) | (carry << (Self::BITS - sub)); - mant_prod - } + (BUintD8::ZERO, BUintD8::ZERO) + } else if sub >= Self::BITS { + (mant_prod.1 >> (sub - Self::BITS), BUintD8::ZERO) + } else { + let mask = BUintD8::MAX >> (Self::BITS - sub); + let carry = mant_prod.1 & mask; + mant_prod.1 >>= sub; + mant_prod.0 = (mant_prod.0 >> sub) | (carry << (Self::BITS - sub)); + mant_prod + } None => (BUintD8::ZERO, BUintD8::ZERO), }; if mant.0.bit(0) { if sticky_bit || mant.0.bit(1) { // Round up - let (sum, carry) = mant.0.overflowing_add(BUintD8::ONE); - mant.0 = sum; - if carry { - mant.1 += BUintD8::ONE; - } + let (sum, carry) = mant.0.overflowing_add(BUintD8::ONE); + mant.0 = sum; + if carry { + mant.1 += BUintD8::ONE; + } + } + } + { + let carry = mant.1.bit(0); + //mant.1 >>= 1 as ExpType; + mant.0 >>= 1 as ExpType; + if carry { + mant.0 |= BIntD8::MIN.to_bits(); } } - { - let carry = mant.1.bit(0); - //mant.1 >>= 1 as ExpType; - mant.0 >>= 1 as ExpType; - if carry { - mant.0 |= BIntD8::MIN.to_bits(); - } - } - - let mut m1b = mant.1.bits(); - if m1b != 0 { - m1b -= 1; - } - let bits = if m1b == 0 { - mant.0.bits() - } else { - m1b + Self::BITS - }; + + let mut m1b = mant.1.bits(); + if m1b != 0 { + m1b -= 1; + } + let bits = if m1b == 0 { + mant.0.bits() + } else { + m1b + Self::BITS + }; if exp == BIntD8::ONE && m1b < Self::MB + 1 { return Self::from_exp_mant(negative, BUintD8::ZERO, mant.0); } //if mant >> Self::MB != BUintD8::ZERO { - mant.0 ^= BUintD8::ONE << Self::MB; - //} + mant.0 ^= BUintD8::ONE << Self::MB; + //} Self::from_exp_mant(negative, exp.to_bits(), mant.0) } } @@ -698,33 +698,33 @@ impl Rem for Float { } crate::nightly::impl_const! { - impl const Neg for Float { - type Output = Self; - - #[inline] - fn neg(mut self) -> Self { - self.bits.digits[W - 1] ^= 1 << (Digit::BITS - 1); - self - } - } + impl const Neg for Float { + type Output = Self; + + #[inline] + fn neg(mut self) -> Self { + self.bits.digits[W - 1] ^= 1 << (Digit::BITS - 1); + self + } + } } crate::nightly::impl_const! { - impl const Neg for &Float { - type Output = Float; - - #[inline] - fn neg(self) -> Float { - (*self).neg() - } - } + impl const Neg for &Float { + type Output = Float; + + #[inline] + fn neg(self) -> Float { + (*self).neg() + } + } } #[cfg(test)] mod tests { use super::*; - use crate::test::test_bignum; - use crate::test::types::{ftest, FTEST}; + use crate::test::test_bignum; + use crate::test::types::{ftest, FTEST}; test_bignum! { function: ::add(a: ftest, b: ftest) @@ -746,7 +746,7 @@ mod tests { function: ::rem(a: ftest, b: ftest) } - test_bignum! { + test_bignum! { function: ::neg(f: ftest) } } \ No newline at end of file diff --git a/src/float/to_str.rs b/src/float/to_str.rs index d87dacd..8ffdab8 100644 --- a/src/float/to_str.rs +++ b/src/float/to_str.rs @@ -1,7 +1,7 @@ use super::Float; impl Float { - + } // TODO: include copyright notice as described in dragon4 paper \ No newline at end of file diff --git a/src/helpers.rs b/src/helpers.rs index e69de29..8b13789 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -0,0 +1 @@ + diff --git a/src/int/cast.rs b/src/int/cast.rs index e44c734..2f06b91 100644 --- a/src/int/cast.rs +++ b/src/int/cast.rs @@ -1,30 +1,30 @@ #[cfg(test)] macro_rules! tests { - ($($int: ty), *) => { - use crate::test::types::*; - use crate::test; - #[allow(unused_imports)] - use crate::test::types::*; - use crate::cast::{CastTo, CastFrom}; + ($($int: ty), *) => { + use crate::test::types::*; + use crate::test; + #[allow(unused_imports)] + use crate::test::types::*; + use crate::cast::{CastTo, CastFrom}; - $( - test::test_from! { - function: <$int as CastFrom>::cast_from, - from_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool, char) - } + $( + test::test_from! { + function: <$int as CastFrom>::cast_from, + from_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool, char) + } - /*#[cfg(feature = "u8_digit")] - test::test_into! { - function: <$int as CastTo>::cast_to, - into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, U8, I8, U16, I16, U32, I32, U64, I64, U128, I128) - }*/ + /*#[cfg(feature = "u8_digit")] + test::test_into! { + function: <$int as CastTo>::cast_to, + into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, U8, I8, U16, I16, U32, I32, U64, I64, U128, I128) + }*/ - test::test_into! { - function: <$int as CastTo>::cast_to, - into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64/* U64, I64, I128, U128*/) - } - )* - }; + test::test_into! { + function: <$int as CastTo>::cast_to, + into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64/* U64, I64, I128, U128*/) + } + )* + }; } #[cfg(test)] diff --git a/src/int/cmp.rs b/src/int/cmp.rs index 9eba817..ee38830 100644 --- a/src/int/cmp.rs +++ b/src/int/cmp.rs @@ -1,65 +1,65 @@ macro_rules! impls { - () => { - #[inline] - pub const fn max(self, other: Self) -> Self { - match self.cmp(&other) { - Ordering::Less | Ordering::Equal => other, - _ => self, - } - } - - #[inline] - pub const fn min(self, other: Self) -> Self { - match self.cmp(&other) { - Ordering::Less | Ordering::Equal => self, - _ => other, - } - } - - #[inline] - pub const fn clamp(self, min: Self, max: Self) -> Self { - assert!(min.le(max)); - if let Ordering::Less = self.cmp(&min) { - min - } else if let Ordering::Greater = self.cmp(&max) { - max - } else { - self - } - } - - #[inline] - pub const fn lt(self, other: Self) -> bool { - match self.cmp(&other) { - Ordering::Less => true, - _ => false, - } - } - - #[inline] - pub const fn le(self, other: Self) -> bool { - match self.cmp(&other) { - Ordering::Less | Ordering::Equal => true, - _ => false, - } - } - - #[inline] - pub const fn gt(self, other: Self) -> bool { - match self.cmp(&other) { - Ordering::Greater => true, - _ => false, - } - } - - #[inline] - pub const fn ge(self, other: Self) -> bool { - match self.cmp(&other) { - Ordering::Greater | Ordering::Equal => true, - _ => false, - } - } - }; + () => { + #[inline] + pub const fn max(self, other: Self) -> Self { + match self.cmp(&other) { + Ordering::Less | Ordering::Equal => other, + _ => self, + } + } + + #[inline] + pub const fn min(self, other: Self) -> Self { + match self.cmp(&other) { + Ordering::Less | Ordering::Equal => self, + _ => other, + } + } + + #[inline] + pub const fn clamp(self, min: Self, max: Self) -> Self { + assert!(min.le(max)); + if let Ordering::Less = self.cmp(&min) { + min + } else if let Ordering::Greater = self.cmp(&max) { + max + } else { + self + } + } + + #[inline] + pub const fn lt(self, other: Self) -> bool { + match self.cmp(&other) { + Ordering::Less => true, + _ => false, + } + } + + #[inline] + pub const fn le(self, other: Self) -> bool { + match self.cmp(&other) { + Ordering::Less | Ordering::Equal => true, + _ => false, + } + } + + #[inline] + pub const fn gt(self, other: Self) -> bool { + match self.cmp(&other) { + Ordering::Greater => true, + _ => false, + } + } + + #[inline] + pub const fn ge(self, other: Self) -> bool { + match self.cmp(&other) { + Ordering::Greater | Ordering::Equal => true, + _ => false, + } + } + }; } pub(crate) use impls; diff --git a/src/int/endian.rs b/src/int/endian.rs index 42dc8b5..c4345de 100644 --- a/src/int/endian.rs +++ b/src/int/endian.rs @@ -1,64 +1,64 @@ #[cfg(test)] #[cfg(feature = "nightly")] macro_rules! test_from_endian_slice { - ($int: ty, $endian: ident) => { - paste::paste! { - quickcheck::quickcheck! { - fn [](int: $int, pad_length: u8) -> quickcheck::TestResult { - type Big = [<$int:upper>]; - type Primitive = crate::test::types::$int; - - use crate::test::TestConvert; - use crate::int::endian; - - // pad_length is greater than the size of the integer in bytes - if pad_length >= Primitive::BITS as u8 / 8 { - return quickcheck::TestResult::discard(); - } - let pad_length = pad_length as usize; - - #[allow(unused_comparisons)] - let mut pad_bits = if int < 0 { - u8::MAX // 1111... - } else { - u8::MIN // 0000... - }; - - let mut bytes = int.[](); // random input bytes - // first, test that the original bytes as slice is converted back to the same integer - let mut passed = TestConvert::into(Big::[](&bytes[..])) == Some(int); - - let bytes_vec = endian::[<$endian _bytes_vec>](&bytes[..], pad_bits, pad_length); // random vector padded with a random amount of bytes - // test that the padded bytes are still converted back to the same integer - passed &= TestConvert::into(Big::[](&bytes_vec[..])) == Some(int); - - // most significant byte position, range of bytes indices to change to padding bits, range of bytes indices that will result in the same integer without the padding bits - let (msb, pad_range, slice_range) = endian::[<$endian _pad>](pad_length, Primitive::BITS); - - pad_bits = { - #[allow(unused_comparisons)] - if Primitive::MIN < 0 && (bytes[msb] as i8).is_negative() { - u8::MAX - } else { - u8::MIN - } - }; - - for item in &mut bytes[pad_range] { - *item = pad_bits; - } - let correct = Some(Big::[](bytes)); - // test that a shortened slice of bytes is converted to the same integer as the shortened slice that is padded to be the same number of bytes as the size of the integer - passed &= Big::[](&bytes[slice_range]) == correct; - - let bytes_vec = endian::[<$endian _bytes_vec>](&bytes[..], pad_bits, pad_length); - passed &= Big::[](&bytes_vec[..]) == correct; - - quickcheck::TestResult::from_bool(passed) - } - } - } - }; + ($int: ty, $endian: ident) => { + paste::paste! { + quickcheck::quickcheck! { + fn [](int: $int, pad_length: u8) -> quickcheck::TestResult { + type Big = [<$int:upper>]; + type Primitive = crate::test::types::$int; + + use crate::test::TestConvert; + use crate::int::endian; + + // pad_length is greater than the size of the integer in bytes + if pad_length >= Primitive::BITS as u8 / 8 { + return quickcheck::TestResult::discard(); + } + let pad_length = pad_length as usize; + + #[allow(unused_comparisons)] + let mut pad_bits = if int < 0 { + u8::MAX // 1111... + } else { + u8::MIN // 0000... + }; + + let mut bytes = int.[](); // random input bytes + // first, test that the original bytes as slice is converted back to the same integer + let mut passed = TestConvert::into(Big::[](&bytes[..])) == Some(int); + + let bytes_vec = endian::[<$endian _bytes_vec>](&bytes[..], pad_bits, pad_length); // random vector padded with a random amount of bytes + // test that the padded bytes are still converted back to the same integer + passed &= TestConvert::into(Big::[](&bytes_vec[..])) == Some(int); + + // most significant byte position, range of bytes indices to change to padding bits, range of bytes indices that will result in the same integer without the padding bits + let (msb, pad_range, slice_range) = endian::[<$endian _pad>](pad_length, Primitive::BITS); + + pad_bits = { + #[allow(unused_comparisons)] + if Primitive::MIN < 0 && (bytes[msb] as i8).is_negative() { + u8::MAX + } else { + u8::MIN + } + }; + + for item in &mut bytes[pad_range] { + *item = pad_bits; + } + let correct = Some(Big::[](bytes)); + // test that a shortened slice of bytes is converted to the same integer as the shortened slice that is padded to be the same number of bytes as the size of the integer + passed &= Big::[](&bytes[slice_range]) == correct; + + let bytes_vec = endian::[<$endian _bytes_vec>](&bytes[..], pad_bits, pad_length); + passed &= Big::[](&bytes_vec[..]) == correct; + + quickcheck::TestResult::from_bool(passed) + } + } + } + }; } #[cfg(test)] diff --git a/src/int/fmt.rs b/src/int/fmt.rs index 37ccb23..ace7a19 100644 --- a/src/int/fmt.rs +++ b/src/int/fmt.rs @@ -1,15 +1,15 @@ #[cfg(test)] macro_rules! format_trait { - ($($method: ident), *) => { - use alloc::string::String; + ($($method: ident), *) => { + use alloc::string::String; - // This trait allows us to use the default tester macro instead of creating a custom one - pub trait Format { - $( - fn $method(&self) -> String; - )* - } - }; + // This trait allows us to use the default tester macro instead of creating a custom one + pub trait Format { + $( + fn $method(&self) -> String; + )* + } + }; } #[cfg(test)] @@ -17,13 +17,13 @@ format_trait!(binary, lower_hex, upper_hex, octal, display, debug, lower_exp, up #[cfg(test)] macro_rules! impl_format_method { - { $($name: ident : $format: literal), * } => { - $( - fn $name(&self) -> String { - format!(concat!("{:", $format, "}"), self) - } - )* - }; + { $($name: ident : $format: literal), * } => { + $( + fn $name(&self) -> String { + format!(concat!("{:", $format, "}"), self) + } + )* + }; } #[cfg(test)] @@ -33,19 +33,19 @@ pub(crate) use impl_format_method; macro_rules! impl_format { ($($ty: ty), *) => { $( - impl Format for $ty { - crate::int::fmt::impl_format_method! { - binary: "b", - lower_hex: "x", - upper_hex: "X", - octal: "o", - display: "", - debug: "?", - lower_exp: "e", - upper_exp: "E" - } - } - )* + impl Format for $ty { + crate::int::fmt::impl_format_method! { + binary: "b", + lower_hex: "x", + upper_hex: "X", + octal: "o", + display: "", + debug: "?", + lower_exp: "e", + upper_exp: "E" + } + } + )* }; } @@ -54,13 +54,13 @@ pub(crate) use impl_format; #[cfg(test)] macro_rules! test_formats { - ($ty: ty; $($name: ident), *) => { - $( - test_bignum! { - function: <$ty as Format>::$name(a: ref &$ty) - } - )* - }; + ($ty: ty; $($name: ident), *) => { + $( + test_bignum! { + function: <$ty as Format>::$name(a: ref &$ty) + } + )* + }; } #[cfg(test)] @@ -68,17 +68,17 @@ pub(crate) use test_formats; #[cfg(test)] macro_rules! tests { - ($ty: ty) => { - use crate::int::fmt::{Format, self}; - use crate::test::{test_bignum, types::*}; - use alloc::string::String; + ($ty: ty) => { + use crate::int::fmt::{Format, self}; + use crate::test::{test_bignum, types::*}; + use alloc::string::String; - paste::paste! { - fmt::impl_format!([<$ty:upper>]); - } + paste::paste! { + fmt::impl_format!([<$ty:upper>]); + } - fmt::test_formats!($ty; binary, lower_hex, upper_hex, octal, display, debug, lower_exp, upper_exp); - }; + fmt::test_formats!($ty; binary, lower_hex, upper_hex, octal, display, debug, lower_exp, upper_exp); + }; } #[cfg(test)] diff --git a/src/int/mod.rs b/src/int/mod.rs index 9b3a927..1ef2772 100644 --- a/src/int/mod.rs +++ b/src/int/mod.rs @@ -33,10 +33,10 @@ macro_rules! tests { function: <$int>::trailing_ones(a: $int) } test_bignum! { - function: <$int>::rotate_left(a: $int, b: u16) + function: <$int>::rotate_left(a: $int, b: u8) } test_bignum! { - function: <$int>::rotate_right(a: $int, b: u16) + function: <$int>::rotate_right(a: $int, b: u8) } test_bignum! { function: <$int>::swap_bytes(a: $int) diff --git a/src/int/numtraits.rs b/src/int/numtraits.rs index b5cc3e0..1d0bda2 100644 --- a/src/int/numtraits.rs +++ b/src/int/numtraits.rs @@ -1,14 +1,14 @@ macro_rules! as_primitive_impl { - ($Int: ident; $($ty: ty), *) => { - $( - impl AsPrimitive<$ty> for $Int { - #[inline] - fn as_(self) -> $ty { - <$ty as crate::cast::CastFrom>::cast_from(self) - } - } - )* - } + ($Int: ident; $($ty: ty), *) => { + $( + impl AsPrimitive<$ty> for $Int { + #[inline] + fn as_(self) -> $ty { + <$ty as crate::cast::CastFrom>::cast_from(self) + } + } + )* + } } pub(crate) use as_primitive_impl; @@ -16,12 +16,12 @@ pub(crate) use as_primitive_impl; macro_rules! num_trait_impl { ($Int: ident, $tr: ident, $method: ident, $ret: ty) => { //crate::nightly::impl_const! { - impl $tr for $Int { - #[inline] - fn $method(&self, rhs: &Self) -> $ret { - Self::$method(*self, *rhs) - } + impl $tr for $Int { + #[inline] + fn $method(&self, rhs: &Self) -> $ret { + Self::$method(*self, *rhs) } + } //} }; } @@ -31,243 +31,243 @@ pub(crate) use num_trait_impl; macro_rules! as_bigint_impl { ([$($ty: ty), *] as $Big: ident) => { $( - //crate::nightly::impl_const! { - impl AsPrimitive<$Big> for $ty { - #[inline] - fn as_(self) -> $Big { - $Big::cast_from(self) - } - } - //} - )* + //crate::nightly::impl_const! { + impl AsPrimitive<$Big> for $ty { + #[inline] + fn as_(self) -> $Big { + $Big::cast_from(self) + } + } + //} + )* } } pub(crate) use as_bigint_impl; macro_rules! impls { - ($Int: ident, $BUint: ident, $BInt: ident) => { - //crate::nightly::impl_const! { - impl Bounded for $Int { - #[inline] - fn min_value() -> Self { - Self::MIN - } - - #[inline] - fn max_value() -> Self { - Self::MAX - } - } - //} - - num_trait_impl!($Int, CheckedAdd, checked_add, Option); - num_trait_impl!($Int, CheckedDiv, checked_div, Option); - num_trait_impl!($Int, CheckedMul, checked_mul, Option); - num_trait_impl!($Int, CheckedRem, checked_rem, Option); - num_trait_impl!($Int, CheckedSub, checked_sub, Option); - - num_trait_impl!($Int, SaturatingAdd, saturating_add, Self); - num_trait_impl!($Int, SaturatingMul, saturating_mul, Self); - num_trait_impl!($Int, SaturatingSub, saturating_sub, Self); - - num_trait_impl!($Int, WrappingAdd, wrapping_add, Self); - num_trait_impl!($Int, WrappingMul, wrapping_mul, Self); - num_trait_impl!($Int, WrappingSub, wrapping_sub, Self); - - //crate::nightly::impl_const! { - impl CheckedNeg for $Int { - #[inline] - fn checked_neg(&self) -> Option { - Self::checked_neg(*self) - } - } - //} - - //crate::nightly::impl_const! { - impl CheckedShl for $Int { - #[inline] - fn checked_shl(&self, rhs: u32) -> Option { - Self::checked_shl(*self, rhs) - } - } - //} - - //crate::nightly::impl_const! { - impl CheckedShr for $Int { - #[inline] - fn checked_shr(&self, rhs: u32) -> Option { - Self::checked_shr(*self, rhs) - } - } - //} - - //crate::nightly::impl_const! { - impl WrappingNeg for $Int { - #[inline] - fn wrapping_neg(&self) -> Self { - Self::wrapping_neg(*self) - } - } - //} - - //crate::nightly::impl_const! { - impl WrappingShl for $Int { - #[inline] - fn wrapping_shl(&self, rhs: u32) -> Self { - Self::wrapping_shl(*self, rhs as ExpType) - } - } - //} - - //crate::nightly::impl_const! { - impl WrappingShr for $Int { - #[inline] - fn wrapping_shr(&self, rhs: u32) -> Self { - Self::wrapping_shr(*self, rhs as ExpType) - } - } - //} - - //crate::nightly::impl_const! { - impl Pow for $Int { - type Output = Self; - - #[inline] - fn pow(self, exp: ExpType) -> Self { - Self::pow(self, exp) - } - } - //} - - //crate::nightly::impl_const! { - impl Saturating for $Int { - #[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) - } - } - //} - - crate::int::numtraits::as_primitive_impl!($Int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); - - crate::int::numtraits::as_bigint_impl!([u8, u16, u32, usize, u64, u128, i8, i16, i32, isize, i64, i128, char, bool] as $Int); - - impl AsPrimitive<$Int> for f32 { - #[inline] - fn as_(self) -> $Int { - $Int::cast_from(self) - } - } - - impl AsPrimitive<$Int> for f64 { - #[inline] - fn as_(self) -> $Int { - $Int::cast_from(self) - } - } - - //crate::nightly::impl_const! { - impl AsPrimitive<$BUint> for $Int { - #[inline] - fn as_(self) -> crate::$BUint { - crate::$BUint::::cast_from(self) - } - } - //} - - //crate::nightly::impl_const! { - impl AsPrimitive<$BInt> for $Int { - #[inline] - fn as_(self) -> crate::$BInt { - crate::$BInt::::cast_from(self) - } - } - //} - - //crate::nightly::impl_const! { - impl MulAdd for $Int { - type Output = Self; - - #[inline] - fn mul_add(self, a: Self, b: Self) -> Self { - (self * a) + b - } - } - //} - - //crate::nightly::impl_const! { - impl MulAddAssign for $Int { - #[inline] - fn mul_add_assign(&mut self, a: Self, b: Self) { - *self = self.mul_add(a, b); - } - } - //} - - impl Num for $Int { - type FromStrRadixErr = crate::errors::ParseIntError; - - #[inline] - fn from_str_radix(string: &str, radix: u32) -> Result { - Self::from_str_radix(string, radix) - } - } - - //crate::nightly::impl_const! { - impl num_traits::NumCast for $Int { - fn from(_n: T) -> Option { - panic!(concat!(crate::errors::err_prefix!(), "`num_traits::NumCast` trait is not supported for ", stringify!($Int))) - } - } - //} - - //crate::nightly::impl_const! { - impl One for $Int { - #[inline] - fn one() -> Self { - Self::ONE - } - - #[inline] - fn is_one(&self) -> bool { - core::cmp::PartialEq::eq(self, &Self::ONE) - } - } - //} - - //crate::nightly::impl_const! { - impl Zero for $Int { - #[inline] - fn zero() -> Self { - Self::ZERO - } - - #[inline] - fn is_zero(&self) -> bool { - Self::is_zero(self) - } - } - //} - } + ($Int: ident, $BUint: ident, $BInt: ident) => { + //crate::nightly::impl_const! { + impl Bounded for $Int { + #[inline] + fn min_value() -> Self { + Self::MIN + } + + #[inline] + fn max_value() -> Self { + Self::MAX + } + } + //} + + num_trait_impl!($Int, CheckedAdd, checked_add, Option); + num_trait_impl!($Int, CheckedDiv, checked_div, Option); + num_trait_impl!($Int, CheckedMul, checked_mul, Option); + num_trait_impl!($Int, CheckedRem, checked_rem, Option); + num_trait_impl!($Int, CheckedSub, checked_sub, Option); + + num_trait_impl!($Int, SaturatingAdd, saturating_add, Self); + num_trait_impl!($Int, SaturatingMul, saturating_mul, Self); + num_trait_impl!($Int, SaturatingSub, saturating_sub, Self); + + num_trait_impl!($Int, WrappingAdd, wrapping_add, Self); + num_trait_impl!($Int, WrappingMul, wrapping_mul, Self); + num_trait_impl!($Int, WrappingSub, wrapping_sub, Self); + + //crate::nightly::impl_const! { + impl CheckedNeg for $Int { + #[inline] + fn checked_neg(&self) -> Option { + Self::checked_neg(*self) + } + } + //} + + //crate::nightly::impl_const! { + impl CheckedShl for $Int { + #[inline] + fn checked_shl(&self, rhs: u32) -> Option { + Self::checked_shl(*self, rhs) + } + } + //} + + //crate::nightly::impl_const! { + impl CheckedShr for $Int { + #[inline] + fn checked_shr(&self, rhs: u32) -> Option { + Self::checked_shr(*self, rhs) + } + } + //} + + //crate::nightly::impl_const! { + impl WrappingNeg for $Int { + #[inline] + fn wrapping_neg(&self) -> Self { + Self::wrapping_neg(*self) + } + } + //} + + //crate::nightly::impl_const! { + impl WrappingShl for $Int { + #[inline] + fn wrapping_shl(&self, rhs: u32) -> Self { + Self::wrapping_shl(*self, rhs as ExpType) + } + } + //} + + //crate::nightly::impl_const! { + impl WrappingShr for $Int { + #[inline] + fn wrapping_shr(&self, rhs: u32) -> Self { + Self::wrapping_shr(*self, rhs as ExpType) + } + } + //} + + //crate::nightly::impl_const! { + impl Pow for $Int { + type Output = Self; + + #[inline] + fn pow(self, exp: ExpType) -> Self { + Self::pow(self, exp) + } + } + //} + + //crate::nightly::impl_const! { + impl Saturating for $Int { + #[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) + } + } + //} + + crate::int::numtraits::as_primitive_impl!($Int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); + + crate::int::numtraits::as_bigint_impl!([u8, u16, u32, usize, u64, u128, i8, i16, i32, isize, i64, i128, char, bool] as $Int); + + impl AsPrimitive<$Int> for f32 { + #[inline] + fn as_(self) -> $Int { + $Int::cast_from(self) + } + } + + impl AsPrimitive<$Int> for f64 { + #[inline] + fn as_(self) -> $Int { + $Int::cast_from(self) + } + } + + //crate::nightly::impl_const! { + impl AsPrimitive<$BUint> for $Int { + #[inline] + fn as_(self) -> crate::$BUint { + crate::$BUint::::cast_from(self) + } + } + //} + + //crate::nightly::impl_const! { + impl AsPrimitive<$BInt> for $Int { + #[inline] + fn as_(self) -> crate::$BInt { + crate::$BInt::::cast_from(self) + } + } + //} + + //crate::nightly::impl_const! { + impl MulAdd for $Int { + type Output = Self; + + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self { + (self * a) + b + } + } + //} + + //crate::nightly::impl_const! { + impl MulAddAssign for $Int { + #[inline] + fn mul_add_assign(&mut self, a: Self, b: Self) { + *self = self.mul_add(a, b); + } + } + //} + + impl Num for $Int { + type FromStrRadixErr = crate::errors::ParseIntError; + + #[inline] + fn from_str_radix(string: &str, radix: u32) -> Result { + Self::from_str_radix(string, radix) + } + } + + //crate::nightly::impl_const! { + impl num_traits::NumCast for $Int { + fn from(_n: T) -> Option { + panic!(concat!(crate::errors::err_prefix!(), "`num_traits::NumCast` trait is not supported for ", stringify!($Int))) + } + } + //} + + //crate::nightly::impl_const! { + impl One for $Int { + #[inline] + fn one() -> Self { + Self::ONE + } + + #[inline] + fn is_one(&self) -> bool { + core::cmp::PartialEq::eq(self, &Self::ONE) + } + } + //} + + //crate::nightly::impl_const! { + impl Zero for $Int { + #[inline] + fn zero() -> Self { + Self::ZERO + } + + #[inline] + fn is_zero(&self) -> bool { + Self::is_zero(self) + } + } + //} + } } pub(crate) use impls; macro_rules! prim_int_method { - { $(fn $name: ident ($($arg: ident $(: $ty: ty)?), *) -> $ret: ty;) * } => { - $( - #[inline] - fn $name($($arg $(: $ty)?), *) -> $ret { - Self::$name($($arg), *) - } - )* - }; + { $(fn $name: ident ($($arg: ident $(: $ty: ty)?), *) -> $ret: ty;) * } => { + $( + #[inline] + fn $name($($arg $(: $ty)?), *) -> $ret { + Self::$name($($arg), *) + } + )* + }; } pub(crate) use prim_int_method; @@ -313,15 +313,15 @@ pub(crate) use prim_int_methods; #[cfg(test)] macro_rules! test_to_primitive { - ($int: ty; $($prim: ty), *) => { - paste::paste! { - $( - test_bignum! { - function: <$int>::[](u: ref &$int) - } - )* - } - }; + ($int: ty; $($prim: ty), *) => { + paste::paste! { + $( + test_bignum! { + function: <$int>::[](u: ref &$int) + } + )* + } + }; } #[cfg(test)] @@ -329,18 +329,18 @@ pub(crate) use test_to_primitive; #[cfg(test)] macro_rules! test_from_primitive { - ($int: ty; $($prim: ty), *) => { - paste::paste! { - $( - test_bignum! { - function: <$int>::[](u: $prim), - cases: [ - (<$int>::MIN as $prim) - ] - } - )* - } - }; + ($int: ty; $($prim: ty), *) => { + paste::paste! { + $( + test_bignum! { + function: <$int>::[](u: $prim), + cases: [ + (<$int>::MIN as $prim) + ] + } + )* + } + }; } #[cfg(test)] @@ -348,79 +348,79 @@ pub(crate) use test_from_primitive; #[cfg(test)] macro_rules! tests { - ($int: ty) => { - use super::*; - use num_traits::PrimInt; - use crate::test::test_bignum; - - test_bignum! { - function: <$int>::sqrt(a: ref &$int), - skip: { - #[allow(unused_comparisons)] - let cond = a < 0; - - cond - } - } - test_bignum! { - function: <$int>::cbrt(a: ref &$int) - } - test_bignum! { - function: <$int>::nth_root(a: ref &$int, n: u32), - skip: n == 0 || { - #[allow(unused_comparisons)] - let cond = a < 0; - - n & 1 == 0 && cond || (n == 1 && cond && a == <$int>::MIN) // second condition is due to an error in the num_integer crate, which incorrectly panics when calculating the first root of i128::MIN - } - } - - use crate::int::numtraits::{test_to_primitive, test_from_primitive}; - - test_to_primitive!($int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); - - test_from_primitive!($int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); - - test_bignum! { - function: <$int as Integer>::gcd(a: ref &$int, b: ref &$int), - skip: { - #[allow(unused_comparisons)] - let cond = <$int>::MIN < 0 && (a == <$int>::MIN && (b == <$int>::MIN || b == 0)) || (b == <$int>::MIN && (a == <$int>::MIN || a == 0)); - cond - } - } - test_bignum! { - function: <$int as Integer>::is_multiple_of(a: ref &$int, b: ref &$int), - skip: { - #[allow(unused_comparisons)] - let cond = b == 0 || a < 0 && a == <$int>::MIN && b == -1i8 as $int; - cond - } - } - test_bignum! { - function: <$int as Integer>::is_even(a: ref &$int) - } - test_bignum! { - function: <$int as Integer>::is_odd(a: ref &$int) - } - - test_bignum! { - function: <$int as PrimInt>::unsigned_shl(a: $int, n: u8), - skip: n >= <$int>::BITS as u8 - } - test_bignum! { - function: <$int as PrimInt>::unsigned_shr(a: $int, n: u8), - skip: n >= <$int>::BITS as u8 - } - test_bignum! { - function: <$int as PrimInt>::signed_shl(a: $int, n: u8), - skip: n >= <$int>::BITS as u8 - } - test_bignum! { - function: <$int as PrimInt>::signed_shr(a: $int, n: u8), - skip: n >= <$int>::BITS as u8 - } - }; + ($int: ty) => { + use super::*; + use num_traits::PrimInt; + use crate::test::test_bignum; + + test_bignum! { + function: <$int>::sqrt(a: ref &$int), + skip: { + #[allow(unused_comparisons)] + let cond = a < 0; + + cond + } + } + test_bignum! { + function: <$int>::cbrt(a: ref &$int) + } + test_bignum! { + function: <$int>::nth_root(a: ref &$int, n: u32), + skip: n == 0 || { + #[allow(unused_comparisons)] + let cond = a < 0; + + n & 1 == 0 && cond || (n == 1 && cond && a == <$int>::MIN) // second condition is due to an error in the num_integer crate, which incorrectly panics when calculating the first root of i128::MIN + } + } + + use crate::int::numtraits::{test_to_primitive, test_from_primitive}; + + test_to_primitive!($int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); + + test_from_primitive!($int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); + + test_bignum! { + function: <$int as Integer>::gcd(a: ref &$int, b: ref &$int), + skip: { + #[allow(unused_comparisons)] + let cond = <$int>::MIN < 0 && (a == <$int>::MIN && (b == <$int>::MIN || b == 0)) || (b == <$int>::MIN && (a == <$int>::MIN || a == 0)); + cond + } + } + test_bignum! { + function: <$int as Integer>::is_multiple_of(a: ref &$int, b: ref &$int), + skip: { + #[allow(unused_comparisons)] + let cond = b == 0 || a < 0 && a == <$int>::MIN && b == -1i8 as $int; + cond + } + } + test_bignum! { + function: <$int as Integer>::is_even(a: ref &$int) + } + test_bignum! { + function: <$int as Integer>::is_odd(a: ref &$int) + } + + test_bignum! { + function: <$int as PrimInt>::unsigned_shl(a: $int, n: u8), + skip: n >= <$int>::BITS as u8 + } + test_bignum! { + function: <$int as PrimInt>::unsigned_shr(a: $int, n: u8), + skip: n >= <$int>::BITS as u8 + } + test_bignum! { + function: <$int as PrimInt>::signed_shl(a: $int, n: u8), + skip: n >= <$int>::BITS as u8 + } + test_bignum! { + function: <$int as PrimInt>::signed_shr(a: $int, n: u8), + skip: n >= <$int>::BITS as u8 + } + }; } #[cfg(test)] diff --git a/src/int/ops.rs b/src/int/ops.rs index 84c5be0..2adc6f2 100644 --- a/src/int/ops.rs +++ b/src/int/ops.rs @@ -1,60 +1,60 @@ macro_rules! op_ref_impl { ($tr: ident <$rhs: ty> for $Struct: ident <$($C: ident),+>, $method: ident) => { - crate::nightly::impl_const! { - impl<$(const $C: usize),+> const $tr<&$rhs> for $Struct <$($C),+> { - type Output = $Struct <$($C),+>; - - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(self, *rhs) - } - } - } - - crate::nightly::impl_const! { - impl<$(const $C: usize),+> const $tr<&$rhs> for &$Struct <$($C),+> { - type Output = $Struct <$($C),+>; - - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, *rhs) - } - } - } - - crate::nightly::impl_const! { - impl<$(const $C: usize),+> const $tr<$rhs> for &$Struct <$($C),+> { - type Output = $Struct <$($C),+>; - - #[inline] - fn $method(self, rhs: $rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, rhs) - } - } - } + crate::nightly::impl_const! { + impl<$(const $C: usize),+> const $tr<&$rhs> for $Struct <$($C),+> { + type Output = $Struct <$($C),+>; + + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(self, *rhs) + } + } + } + + crate::nightly::impl_const! { + impl<$(const $C: usize),+> const $tr<&$rhs> for &$Struct <$($C),+> { + type Output = $Struct <$($C),+>; + + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, *rhs) + } + } + } + + crate::nightly::impl_const! { + impl<$(const $C: usize),+> const $tr<$rhs> for &$Struct <$($C),+> { + type Output = $Struct <$($C),+>; + + #[inline] + fn $method(self, rhs: $rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, rhs) + } + } + } } } pub(crate) use op_ref_impl; macro_rules! assign_op_impl { ($OpTrait: ident, $AssignTrait: ident<$rhs: ty> for $Struct: ident, $assign: ident, $op: ident) => { - crate::nightly::impl_const! { - impl const $AssignTrait<$rhs> for $Struct { - #[inline] - fn $assign(&mut self, rhs: $rhs) { - *self = $OpTrait::$op(*self, rhs); - } - } - } - - crate::nightly::impl_const! { - impl const $AssignTrait<&$rhs> for $Struct { - #[inline] - fn $assign(&mut self, rhs: &$rhs) { - self.$assign(*rhs); - } - } - } + crate::nightly::impl_const! { + impl const $AssignTrait<$rhs> for $Struct { + #[inline] + fn $assign(&mut self, rhs: $rhs) { + *self = $OpTrait::$op(*self, rhs); + } + } + } + + crate::nightly::impl_const! { + impl const $AssignTrait<&$rhs> for $Struct { + #[inline] + fn $assign(&mut self, rhs: &$rhs) { + self.$assign(*rhs); + } + } + } crate::int::ops::op_ref_impl!($OpTrait<$rhs> for $Struct, $op); } @@ -73,7 +73,7 @@ macro_rules! shift_impl { self.$method(rhs as ExpType) } } - })* + })* } } pub(crate) use shift_impl; @@ -95,83 +95,83 @@ macro_rules! try_shift_impl { self.$method(rhs) } } - })* + })* } } pub(crate) use try_shift_impl; macro_rules! shift_self_impl { ($Struct: ident, $BUint: ident, $BInt: ident; $tr: tt<$rhs: tt>, $method: ident, $assign_tr: tt, $assign_method: ident, $err: expr) => { - crate::nightly::impl_const! { - impl const $tr<$rhs> for $Struct { - type Output = Self; - - #[inline] - fn $method(self, rhs: $rhs) -> Self { - use crate::ExpType; - let rhs: ExpType = crate::errors::result_expect!(ExpType::try_from(rhs), crate::errors::err_msg!($err)); - self.$method(rhs) - } - } - } - - crate::nightly::impl_const! { - impl const $tr<&$rhs> for $Struct { - type Output = $Struct; - - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(self, *rhs) - } - } - } - - crate::nightly::impl_const! { - impl const $tr<&$rhs> for &$Struct { - type Output = $Struct; - - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, *rhs) - } - } - } - - crate::nightly::impl_const! { - impl const $tr<$rhs> for &$Struct { - type Output = $Struct; - - #[inline] - fn $method(self, rhs: $rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const $assign_tr<$rhs> for $Struct { - #[inline] - fn $assign_method(&mut self, rhs: $rhs) { - *self = $tr::<$rhs>::$method(*self, rhs); - } - } - } - - crate::nightly::impl_const! { - impl const $assign_tr<&$rhs> for $Struct { - #[inline] - fn $assign_method(&mut self, rhs: &$rhs) { - (*self).$assign_method(*rhs); - } - } - } + crate::nightly::impl_const! { + impl const $tr<$rhs> for $Struct { + type Output = Self; + + #[inline] + fn $method(self, rhs: $rhs) -> Self { + use crate::ExpType; + let rhs: ExpType = crate::errors::result_expect!(ExpType::try_from(rhs), crate::errors::err_msg!($err)); + self.$method(rhs) + } + } + } + + crate::nightly::impl_const! { + impl const $tr<&$rhs> for $Struct { + type Output = $Struct; + + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(self, *rhs) + } + } + } + + crate::nightly::impl_const! { + impl const $tr<&$rhs> for &$Struct { + type Output = $Struct; + + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, *rhs) + } + } + } + + crate::nightly::impl_const! { + impl const $tr<$rhs> for &$Struct { + type Output = $Struct; + + #[inline] + fn $method(self, rhs: $rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const $assign_tr<$rhs> for $Struct { + #[inline] + fn $assign_method(&mut self, rhs: $rhs) { + *self = $tr::<$rhs>::$method(*self, rhs); + } + } + } + + crate::nightly::impl_const! { + impl const $assign_tr<&$rhs> for $Struct { + #[inline] + fn $assign_method(&mut self, rhs: &$rhs) { + (*self).$assign_method(*rhs); + } + } + } } } pub(crate) use shift_self_impl; macro_rules! all_shift_impls { ($Struct: ident, $BUint: ident, $BInt: ident) => { - crate::int::ops::try_shift_impl!( + crate::int::ops::try_shift_impl!( $Struct, $BUint, $BInt; Shl, shl, @@ -307,127 +307,125 @@ macro_rules! shift_assign_ops { pub(crate) use shift_assign_ops; macro_rules! trait_fillers { - () => { - #[inline] - pub const fn add(self, rhs: Self) -> Self { - #[cfg(debug_assertions)] - return crate::errors::option_expect!(self.checked_add(rhs), "attempt to add with overflow"); - - #[cfg(not(debug_assertions))] - self.wrapping_add(rhs) - } - - #[inline] - pub const fn mul(self, rhs: Self) -> Self { - #[cfg(debug_assertions)] - return crate::errors::option_expect!(self.checked_mul(rhs), "attempt to multiply with overflow"); - - #[cfg(not(debug_assertions))] - self.wrapping_mul(rhs) - } - - crate::nightly::const_fns! { - #[inline] - pub const fn shl(self, rhs: ExpType) -> Self { - #[cfg(debug_assertions)] - return crate::errors::option_expect!(self.checked_shl(rhs), "attempt to shift left with overflow"); - - #[cfg(not(debug_assertions))] - self.wrapping_shl(rhs) - } - - #[inline] - pub const fn shr(self, rhs: ExpType) -> Self { - #[cfg(debug_assertions)] - return crate::errors::option_expect!(self.checked_shr(rhs), "attempt to shift left with overflow"); - - #[cfg(not(debug_assertions))] - self.wrapping_shr(rhs) - } - } - - #[inline] - pub const fn sub(self, rhs: Self) -> Self { - #[cfg(debug_assertions)] - return crate::errors::option_expect!(self.checked_sub(rhs), "attempt to subtract with overflow"); - - #[cfg(not(debug_assertions))] - self.wrapping_sub(rhs) - } - }; + () => { + #[inline] + pub const fn add(self, rhs: Self) -> Self { + #[cfg(debug_assertions)] + return crate::errors::option_expect!(self.checked_add(rhs), "attempt to add with overflow"); + + #[cfg(not(debug_assertions))] + self.wrapping_add(rhs) + } + + #[inline] + pub const fn mul(self, rhs: Self) -> Self { + #[cfg(debug_assertions)] + return crate::errors::option_expect!(self.checked_mul(rhs), "attempt to multiply with overflow"); + + #[cfg(not(debug_assertions))] + self.wrapping_mul(rhs) + } + + #[inline] + pub const fn shl(self, rhs: ExpType) -> Self { + #[cfg(debug_assertions)] + return crate::errors::option_expect!(self.checked_shl(rhs), "attempt to shift left with overflow"); + + #[cfg(not(debug_assertions))] + self.wrapping_shl(rhs) + } + + #[inline] + pub const fn shr(self, rhs: ExpType) -> Self { + #[cfg(debug_assertions)] + return crate::errors::option_expect!(self.checked_shr(rhs), "attempt to shift left with overflow"); + + #[cfg(not(debug_assertions))] + self.wrapping_shr(rhs) + } + + #[inline] + pub const fn sub(self, rhs: Self) -> Self { + #[cfg(debug_assertions)] + return crate::errors::option_expect!(self.checked_sub(rhs), "attempt to subtract with overflow"); + + #[cfg(not(debug_assertions))] + self.wrapping_sub(rhs) + } + }; } pub(crate) use trait_fillers; macro_rules! impls { ($Struct: ident, $BUint: ident, $BInt: ident) => { - crate::nightly::impl_const! { - impl const Add for $Struct { - type Output = Self; - - #[inline] - fn add(self, rhs: Self) -> Self { - Self::add(self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const Mul for $Struct { - type Output = Self; - - #[inline] - fn mul(self, rhs: Self) -> Self { - Self::mul(self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const Not for &$Struct { - type Output = $Struct; - - #[inline] - fn not(self) -> $Struct { - (*self).not() // TODO: maybe use separate impl for this as well - } - } - } - - crate::nightly::impl_const! { - impl const Shl for $Struct { - type Output = Self; - - #[inline] - fn shl(self, rhs: ExpType) -> Self { - Self::shl(self, rhs) - } - } - } - - crate::nightly::impl_const! { - impl const Shr for $Struct { - type Output = Self; - - #[inline] - fn shr(self, rhs: ExpType) -> Self { - Self::shr(self, rhs) - } - } - } - - crate::int::ops::all_shift_impls!($Struct, $BUint, $BInt); - - crate::nightly::impl_const! { - impl const Sub for $Struct { - type Output = Self; - - #[inline] - fn sub(self, rhs: Self) -> Self { - Self::sub(self, rhs) - } - } - } + crate::nightly::impl_const! { + impl const Add for $Struct { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self { + Self::add(self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const Mul for $Struct { + type Output = Self; + + #[inline] + fn mul(self, rhs: Self) -> Self { + Self::mul(self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const Not for &$Struct { + type Output = $Struct; + + #[inline] + fn not(self) -> $Struct { + (*self).not() // TODO: maybe use separate impl for this as well + } + } + } + + crate::nightly::impl_const! { + impl const Shl for $Struct { + type Output = Self; + + #[inline] + fn shl(self, rhs: ExpType) -> Self { + Self::shl(self, rhs) + } + } + } + + crate::nightly::impl_const! { + impl const Shr for $Struct { + type Output = Self; + + #[inline] + fn shr(self, rhs: ExpType) -> Self { + Self::shr(self, rhs) + } + } + } + + crate::int::ops::all_shift_impls!($Struct, $BUint, $BInt); + + crate::nightly::impl_const! { + impl const Sub for $Struct { + type Output = Self; + + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::sub(self, rhs) + } + } + } crate::int::ops::assign_op_impl!(Add, AddAssign<$Struct> for $Struct, add_assign, add); crate::int::ops::assign_op_impl!(BitAnd, BitAndAssign<$Struct> for $Struct, bitand_assign, bitand); diff --git a/src/int/radix.rs b/src/int/radix.rs index 295d84d..685e27f 100644 --- a/src/int/radix.rs +++ b/src/int/radix.rs @@ -2,7 +2,11 @@ macro_rules! assert_range { ($radix: expr, $max: expr) => { assert!( $radix >= 2 && $radix <= $max, - crate::errors::err_msg!(concat!("Radix must be in range [2, ", stringify!($max), "]")) + crate::errors::err_msg!(concat!( + "Radix must be in range [2, ", + stringify!($max), + "]" + )) ) }; } diff --git a/src/int/unchecked.rs b/src/int/unchecked.rs index c638bad..0edaeab 100644 --- a/src/int/unchecked.rs +++ b/src/int/unchecked.rs @@ -2,44 +2,44 @@ macro_rules! impls { ($Int: ident, $sign: ident) => { #[doc = doc::unchecked::impl_desc!()] impl $Int { - crate::nightly::const_fns! { - #[doc = doc::unchecked::unchecked_add!($sign)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { - self.checked_add(rhs).unwrap_unchecked() - } + crate::nightly::const_fns! { + #[doc = doc::unchecked::unchecked_add!($sign)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const unsafe fn unchecked_add(self, rhs: Self) -> Self { + self.checked_add(rhs).unwrap_unchecked() + } - #[doc = doc::unchecked::unchecked_sub!($sign)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { - self.checked_sub(rhs).unwrap_unchecked() - } + #[doc = doc::unchecked::unchecked_sub!($sign)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self { + self.checked_sub(rhs).unwrap_unchecked() + } - #[doc = doc::unchecked::unchecked_mul!($sign)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { - self.checked_mul(rhs).unwrap_unchecked() - } + #[doc = doc::unchecked::unchecked_mul!($sign)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self { + self.checked_mul(rhs).unwrap_unchecked() + } - #[doc = doc::unchecked::unchecked_shl!($sign)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self { - let rhs = rhs.to_exp_type().unwrap_unchecked(); - self.checked_shl(rhs).unwrap_unchecked() - } + #[doc = doc::unchecked::unchecked_shl!($sign)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self { + let rhs = rhs.to_exp_type().unwrap_unchecked(); + self.checked_shl(rhs).unwrap_unchecked() + } - #[doc = doc::unchecked::unchecked_shr!($sign)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self { - let rhs = rhs.to_exp_type().unwrap_unchecked(); - self.checked_shr(rhs).unwrap_unchecked() - } - } + #[doc = doc::unchecked::unchecked_shr!($sign)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self { + let rhs = rhs.to_exp_type().unwrap_unchecked(); + self.checked_shr(rhs).unwrap_unchecked() + } + } } }; } diff --git a/src/lib.rs b/src/lib.rs index 4bd14f4..e32f797 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ const_mut_refs, const_maybe_uninit_as_mut_ptr, const_swap, - const_option_ext + const_option_ext ) )] #![cfg_attr( @@ -17,11 +17,11 @@ int_roundings, float_minimum_maximum, wrapping_next_power_of_two, - float_next_up_down, + float_next_up_down, ) )] #![doc = include_str!("../README.md")] -#![no_std] +#![cfg_attr(not(feature = "arbitrary"), no_std)] #[macro_use] extern crate alloc; @@ -33,10 +33,10 @@ pub mod cast; mod digit; mod doc; pub mod errors; +pub mod helpers; mod int; mod nightly; pub mod prelude; -pub mod helpers; #[cfg(feature = "rand")] pub mod random; @@ -49,7 +49,6 @@ mod float; #[cfg(feature = "nightly")] pub use float::Float;*/ - #[cfg(test)] mod test; @@ -83,8 +82,8 @@ macro_rules! main_impl { pub(crate) use main_impl; mod bigints { - pub use crate::bint::{BInt, BIntD16, BIntD32, BIntD8}; - pub use crate::buint::{BUint, BUintD16, BUintD32, BUintD8}; + pub use crate::bint::{BInt, BIntD16, BIntD32, BIntD8}; + pub use crate::buint::{BUint, BUintD16, BUintD32, BUintD8}; } -pub use bigints::*; \ No newline at end of file +pub use bigints::*; diff --git a/src/nightly.rs b/src/nightly.rs index 2faeb97..0c04691 100644 --- a/src/nightly.rs +++ b/src/nightly.rs @@ -1,71 +1,71 @@ macro_rules! const_fn { - { $(#[$attr: meta]) * $vis: vis const $($rest: tt) + } => { - #[cfg(feature = "nightly")] - $(#[$attr]) * - #[doc = "\n\nNB: this method is only `const` when the `nightly` feature is enabled."] - $vis const $($rest) + + { $(#[$attr: meta]) * $vis: vis const $($rest: tt) + } => { + #[cfg(feature = "nightly")] + $(#[$attr]) * + #[doc = "\n\nNB: this method is only `const` when the `nightly` feature is enabled."] + $vis const $($rest) + - #[cfg(not(feature = "nightly"))] - $(#[$attr]) * - $vis $($rest) + - }; + #[cfg(not(feature = "nightly"))] + $(#[$attr]) * + $vis $($rest) + + }; } pub(crate) use const_fn; macro_rules! const_fns { - { $($(#[$attr: meta]) * $vis: vis const fn $name: ident ($($args: tt) *) -> $ret : ty { $($f: tt) + }) * } => { - $( - crate::nightly::const_fn! { - $(#[$attr]) * $vis const fn $name ($($args) *) -> $ret { $($f) + } - } - )* - }; - { $($(#[$attr: meta]) * $vis: vis const unsafe fn $name: ident ($($args: tt) *) -> $ret : ty { $($f: tt) + }) * } => { - $( - crate::nightly::const_fn! { - $(#[$attr]) * $vis const unsafe fn $name ($($args) *) -> $ret { $($f) + } - } - )* - }; + { $($(#[$attr: meta]) * $vis: vis const fn $name: ident ($($args: tt) *) -> $ret : ty { $($f: tt) + }) * } => { + $( + crate::nightly::const_fn! { + $(#[$attr]) * $vis const fn $name ($($args) *) -> $ret { $($f) + } + } + )* + }; + { $($(#[$attr: meta]) * $vis: vis const unsafe fn $name: ident ($($args: tt) *) -> $ret : ty { $($f: tt) + }) * } => { + $( + crate::nightly::const_fn! { + $(#[$attr]) * $vis const unsafe fn $name ($($args) *) -> $ret { $($f) + } + } + )* + }; } pub(crate) use const_fns; #[cfg(feature = "nightly")] macro_rules! impl_const { - { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { - impl $(<$(const $C: $ty), +>)? $($tt) + - } + { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { + impl $(<$(const $C: $ty), +>)? $($tt) + + } } #[cfg(not(feature = "nightly"))] macro_rules! impl_const { - { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { - impl $(<$(const $C: $ty), +>)? $($tt) + - } + { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { + impl $(<$(const $C: $ty), +>)? $($tt) + + } } pub(crate) use impl_const; macro_rules! option_try { - ($e: expr) => { - match $e { - Some(v) => v, - None => return None, - } - }; + ($e: expr) => { + match $e { + Some(v) => v, + None => return None, + } + }; } pub(crate) use option_try; macro_rules! ok { - { $e: expr } => { - match $e { - Ok(v) => Some(v), - Err(_) => None, - } - }; + { $e: expr } => { + match $e { + Ok(v) => Some(v), + Err(_) => None, + } + }; } -pub(crate) use ok; \ No newline at end of file +pub(crate) use ok; diff --git a/src/random.rs b/src/random.rs index 5dd7275..6d0a9cd 100644 --- a/src/random.rs +++ b/src/random.rs @@ -210,52 +210,52 @@ macro_rules! uniform_int_impl { #[cfg(test)] macro_rules! test_random { - ($int: ty; $($Rng: ty), *) => { - paste::paste! { - $( - quickcheck::quickcheck! { - #[allow(non_snake_case)] - fn [](seed: u64) -> bool { - use crate::test::TestConvert; - use crate::test::types::*; - use rand::Rng; - use rand::rngs::$Rng; + ($int: ty; $($Rng: ty), *) => { + paste::paste! { + $( + quickcheck::quickcheck! { + #[allow(non_snake_case)] + fn [](seed: u64) -> bool { + use crate::test::TestConvert; + use crate::test::types::*; + use rand::Rng; + use rand::rngs::$Rng; - let (mut rng, mut rng2) = seeded_rngs::<$Rng>(seed); + let (mut rng, mut rng2) = seeded_rngs::<$Rng>(seed); - let big = rng.gen::<[<$int:upper>]>(); - let primitive = rng2.gen::<$int>(); + let big = rng.gen::<[<$int:upper>]>(); + let primitive = rng2.gen::<$int>(); - TestConvert::into(big) == TestConvert::into(primitive) - } + TestConvert::into(big) == TestConvert::into(primitive) + } - #[allow(non_snake_case)] - fn [](seed: u64) -> bool { - use crate::test::TestConvert; - use rand::Fill; - use rand::rngs::$Rng; + #[allow(non_snake_case)] + fn [](seed: u64) -> bool { + use crate::test::TestConvert; + use rand::Fill; + use rand::rngs::$Rng; - const SLICE_LENGTH: usize = 20; + const SLICE_LENGTH: usize = 20; - let (mut rng, mut rng2) = seeded_rngs::<$Rng>(seed); + let (mut rng, mut rng2) = seeded_rngs::<$Rng>(seed); - let mut big_array = [<[<$int:upper>]>::MIN; SLICE_LENGTH]; - let mut primitive_array = [<$int>::MIN; SLICE_LENGTH]; + let mut big_array = [<[<$int:upper>]>::MIN; SLICE_LENGTH]; + let mut primitive_array = [<$int>::MIN; SLICE_LENGTH]; - crate::random::try_fill_slice(&mut big_array, &mut rng).unwrap(); + crate::random::try_fill_slice(&mut big_array, &mut rng).unwrap(); - primitive_array.try_fill(&mut rng2).unwrap(); + primitive_array.try_fill(&mut rng2).unwrap(); - big_array - .into_iter() - .zip(primitive_array.into_iter()) - .all(|(big, primitive)| { - TestConvert::into(big) == TestConvert::into(primitive) - }) - } + big_array + .into_iter() + .zip(primitive_array.into_iter()) + .all(|(big, primitive)| { + TestConvert::into(big) == TestConvert::into(primitive) + }) + } - #[allow(non_snake_case)] - fn [](seed: u64, min: $int, max: $int) -> quickcheck::TestResult { + #[allow(non_snake_case)] + fn [](seed: u64, min: $int, max: $int) -> quickcheck::TestResult { if min >= max { return quickcheck::TestResult::discard(); } @@ -324,8 +324,8 @@ macro_rules! random { #[cfg(test)] paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; + mod [<$Digit _digit_tests>] { + use crate::test::types::big_types::$Digit::*; use crate::test::types::*; use rand::SeedableRng; @@ -342,4 +342,4 @@ macro_rules! random { }; } -crate::macro_impl!(random); \ No newline at end of file +crate::macro_impl!(random); diff --git a/src/test/convert.rs b/src/test/convert.rs index a7745fb..22bd6d1 100644 --- a/src/test/convert.rs +++ b/src/test/convert.rs @@ -11,28 +11,28 @@ pub trait TestConvert { macro_rules! test_convert_big { ($($big: ty), *; $output: ty) => { $( - impl TestConvert for $big { - type Output = $output; - - #[inline] - fn into(self) -> Self::Output { - Self::Output::cast_from(self) - } - } - )* + impl TestConvert for $big { + type Output = $output; + + #[inline] + fn into(self) -> Self::Output { + Self::Output::cast_from(self) + } + } + )* }; } macro_rules! test_convert_bigints { - ($($bits: literal), *) => { - paste::paste! { - $( - test_convert_big!(BUint<{$bits / 64}>, BUintD32<{$bits / 32}>, BUintD16<{$bits / 16}>, BUintD8<{$bits / 8}>; []); + ($($bits: literal), *) => { + paste::paste! { + $( + test_convert_big!(BUint<{$bits / 64}>, BUintD32<{$bits / 32}>, BUintD16<{$bits / 16}>, BUintD8<{$bits / 8}>; []); - test_convert_big!(BInt<{$bits / 64}>, BIntD32<{$bits / 32}>, BIntD16<{$bits / 16}>, BIntD8<{$bits / 8}>; []); - )* - } - }; + test_convert_big!(BInt<{$bits / 64}>, BIntD32<{$bits / 32}>, BIntD16<{$bits / 16}>, BIntD8<{$bits / 8}>; []); + )* + } + }; } test_convert_bigints!(128, 64); @@ -69,26 +69,26 @@ impl TestConvert for f32 { /*#[cfg(feature = "nightly")] impl TestConvert for crate::float::F64 { - type Output = u64; + type Output = u64; - #[inline] - fn into(self) -> Self::Output { - use crate::cast::As; - - self.to_bits().as_() - } + #[inline] + fn into(self) -> Self::Output { + use crate::cast::As; + + self.to_bits().as_() + } } #[cfg(feature = "nightly")] impl TestConvert for crate::float::F32 { - type Output = u32; - - #[inline] - fn into(self) -> Self::Output { - use crate::cast::As; - - self.to_bits().as_() - } + type Output = u32; + + #[inline] + fn into(self) -> Self::Output { + use crate::cast::As; + + self.to_bits().as_() + } }*/ impl TestConvert for (T, U) { diff --git a/src/test/macros.rs b/src/test/macros.rs index 55f29c9..272d2cc 100644 --- a/src/test/macros.rs +++ b/src/test/macros.rs @@ -1,78 +1,78 @@ macro_rules! test_bignum { - { - function: <$primitive: ty $(as $Trait: ident $(<$($gen: ty), *>)?)?> :: $function: ident ($($param: ident : $(ref $re: tt)? $ty: ty), *) - $(, skip: $skip: expr)? - } => { - paste::paste! { - quickcheck::quickcheck! { - #[allow(non_snake_case)] - fn []($($param : $ty), *) -> quickcheck::TestResult { - $(if $skip { - return quickcheck::TestResult::discard(); - })? - - let (big, primitive) = crate::test::results!(<$primitive $(as $Trait $(<$($gen), *>)?)?>::$function ($($($re)? Into::into($param)), *)); - - quickcheck::TestResult::from_bool(big == primitive) - } - } - } - }; - { - function: <$primitive: ty $(as $Trait: ty)?> :: $function: ident, - cases: [ + { + function: <$primitive: ty $(as $Trait: ident $(<$($gen: ty), *>)?)?> :: $function: ident ($($param: ident : $(ref $re: tt)? $ty: ty), *) + $(, skip: $skip: expr)? + } => { + paste::paste! { + quickcheck::quickcheck! { + #[allow(non_snake_case)] + fn []($($param : $ty), *) -> quickcheck::TestResult { + $(if $skip { + return quickcheck::TestResult::discard(); + })? + + let (big, primitive) = crate::test::results!(<$primitive $(as $Trait $(<$($gen), *>)?)?>::$function ($($($re)? Into::into($param)), *)); + + quickcheck::TestResult::from_bool(big == primitive) + } + } + } + }; + { + function: <$primitive: ty $(as $Trait: ty)?> :: $function: ident, + cases: [ $(($($(ref $re2: tt)? $arg: expr), *)), * ] - } => { - paste::paste! { - #[test] - fn []() { - $( - let (big, primitive) = crate::test::results!(<$primitive> :: $function ($($($re2)? Into::into($arg)), *)); - assert_eq!(big, primitive); - )* - } - } - }; - { - function: <$primitive: ty $(as $Trait: ty)?> :: $function: ident ($($param: ident : $(ref $re: tt)? $ty: ty), *) - $(, skip: $skip: expr)? - , cases: [ + } => { + paste::paste! { + #[test] + fn []() { + $( + let (big, primitive) = crate::test::results!(<$primitive> :: $function ($($($re2)? Into::into($arg)), *)); + assert_eq!(big, primitive); + )* + } + } + }; + { + function: <$primitive: ty $(as $Trait: ty)?> :: $function: ident ($($param: ident : $(ref $re: tt)? $ty: ty), *) + $(, skip: $skip: expr)? + , cases: [ $(($($(ref $re2: tt)? $arg: expr), *)), * ] - } => { - crate::test::test_bignum! { - function: <$primitive $(as $Trait)?> :: $function, - cases: [ - $(($($(ref $re2)? $arg), *)), * - ] - } - crate::test::test_bignum! { - function: <$primitive $(as $Trait)?> :: $function ($($param : $(ref $re)? $ty), *) - $(, skip: $skip)? - } - }; + } => { + crate::test::test_bignum! { + function: <$primitive $(as $Trait)?> :: $function, + cases: [ + $(($($(ref $re2)? $arg), *)), * + ] + } + crate::test::test_bignum! { + function: <$primitive $(as $Trait)?> :: $function ($($param : $(ref $re)? $ty), *) + $(, skip: $skip)? + } + }; } pub(crate) use test_bignum; macro_rules! results { - (<$primitive: ty $(as $Trait: ty)?> :: $function: ident ($($arg: expr), *)) => { - paste::paste! { - { - use crate::test::types; - let big_result = <[<$primitive:upper>] $(as $Trait)?>::$function( - $($arg), * - ); - let prim_result = ::$function( - $($arg), * - ); - - use crate::test::TestConvert; - (TestConvert::into(big_result), TestConvert::into(prim_result)) - } - } - }; + (<$primitive: ty $(as $Trait: ty)?> :: $function: ident ($($arg: expr), *)) => { + paste::paste! { + { + use crate::test::types; + let big_result = <[<$primitive:upper>] $(as $Trait)?>::$function( + $($arg), * + ); + let prim_result = ::$function( + $($arg), * + ); + + use crate::test::TestConvert; + (TestConvert::into(big_result), TestConvert::into(prim_result)) + } + } + }; } pub(crate) use results; @@ -82,11 +82,11 @@ macro_rules! test_from { function: <$primitive: ty as $Trait: ident>:: $name: ident, from_types: ($($from_type: ty), *) } => { - $( - crate::test::test_bignum! { - function: < $primitive as $Trait<$from_type> >::$name(from: $from_type) - } - )* + $( + crate::test::test_bignum! { + function: < $primitive as $Trait<$from_type> >::$name(from: $from_type) + } + )* } } @@ -97,13 +97,13 @@ macro_rules! test_into { function: <$primitive: ty as $Trait: ident>:: $name: ident, into_types: ($($into_type: ty), *) } => { - paste::paste! { - $( - crate::test::test_bignum! { - function: < $primitive as $Trait<$into_type> >::$name(from: $primitive) - } - )* - } + paste::paste! { + $( + crate::test::test_bignum! { + function: < $primitive as $Trait<$into_type> >::$name(from: $primitive) + } + )* + } } } @@ -115,10 +115,10 @@ pub struct Radix(pub u32); use quickcheck::{Arbitrary, Gen}; impl Arbitrary for Radix { - fn arbitrary(g: &mut Gen) -> Self { - let radix = (u32::arbitrary(g) % (MAX - 2)) + 2; - Self(radix) - } + fn arbitrary(g: &mut Gen) -> Self { + let radix = (u32::arbitrary(g) % (MAX - 2)) + 2; + Self(radix) + } } macro_rules! quickcheck_from_to_radix { @@ -126,7 +126,7 @@ macro_rules! quickcheck_from_to_radix { paste::paste! { quickcheck::quickcheck! { fn [](u: crate::test::types::$primitive, radix: crate::test::Radix<$max>) -> quickcheck::TestResult { - let radix = radix.0; + let radix = radix.0; let u = <[<$primitive:upper>]>::from(u); let v = u.[](radix as u32); let u1 = <[<$primitive:upper>]>::[](&v, radix as u32).unwrap_or(!u); @@ -153,54 +153,54 @@ macro_rules! debug_skip { pub(crate) use debug_skip; macro_rules! quickcheck_from_str_radix { - { $primitive: ident, $sign1: literal | $sign2: literal } => { - quickcheck::quickcheck! { - fn quickcheck_from_str_radix(buf: crate::test::U8ArrayWrapper<{::BITS as usize / 4}>, radix: crate::test::Radix<36>, leading_sign: bool) -> quickcheck::TestResult { - use alloc::string::String; - - let radix = radix.0; - - fn byte_to_char(b: u8) -> char { - if b < 10 { - (b + 48) as char - } else { - (b + 87) as char - } - } - - let leading_sign = if leading_sign { - $sign1 - } else { - $sign2 - }; - - let mut s2 = buf.0.into_iter().map(|b| byte_to_char(b % radix as u8)).collect::(); - s2.insert_str(0, leading_sign); - - let (big, primitive) = crate::test::results!(<$primitive>::from_str_radix(&s2, radix as u32)); - - quickcheck::TestResult::from_bool(big == primitive) - } - } - } + { $primitive: ident, $sign1: literal | $sign2: literal } => { + quickcheck::quickcheck! { + fn quickcheck_from_str_radix(buf: crate::test::U8ArrayWrapper<{::BITS as usize / 4}>, radix: crate::test::Radix<36>, leading_sign: bool) -> quickcheck::TestResult { + use alloc::string::String; + + let radix = radix.0; + + fn byte_to_char(b: u8) -> char { + if b < 10 { + (b + 48) as char + } else { + (b + 87) as char + } + } + + let leading_sign = if leading_sign { + $sign1 + } else { + $sign2 + }; + + let mut s2 = buf.0.into_iter().map(|b| byte_to_char(b % radix as u8)).collect::(); + s2.insert_str(0, leading_sign); + + let (big, primitive) = crate::test::results!(<$primitive>::from_str_radix(&s2, radix as u32)); + + quickcheck::TestResult::from_bool(big == primitive) + } + } + } } pub(crate) use quickcheck_from_str_radix; macro_rules! quickcheck_from_str { - ($primitive: ty) => { - quickcheck::quickcheck! { - fn quickcheck_from_str(n: $primitive) -> bool { - use crate::alloc::string::ToString; - use core::str::FromStr; - - let s = n.to_string(); - let (big, primitive) = crate::test::results!(<$primitive>::from_str(&s)); - - big == primitive - } - } - } + ($primitive: ty) => { + quickcheck::quickcheck! { + fn quickcheck_from_str(n: $primitive) -> bool { + use crate::alloc::string::ToString; + use core::str::FromStr; + + let s = n.to_string(); + let (big, primitive) = crate::test::results!(<$primitive>::from_str(&s)); + + big == primitive + } + } + }; } -pub(crate) use quickcheck_from_str; \ No newline at end of file +pub(crate) use quickcheck_from_str; diff --git a/src/test/mod.rs b/src/test/mod.rs index c697e1a..7d965ae 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -20,13 +20,13 @@ impl From> for [u8; N] { use quickcheck::{Arbitrary, Gen}; impl Arbitrary for U8ArrayWrapper { - fn arbitrary(g: &mut Gen) -> Self { - let mut arr = [0u8; N]; - for x in arr.iter_mut() { - *x = u8::arbitrary(g); - } - Self(arr) - } + fn arbitrary(g: &mut Gen) -> Self { + let mut arr = [0u8; N]; + for x in arr.iter_mut() { + *x = u8::arbitrary(g); + } + Self(arr) + } } use core::fmt::{self, Debug, Formatter}; diff --git a/src/test/types.rs b/src/test/types.rs index 061d956..f17c985 100644 --- a/src/test/types.rs +++ b/src/test/types.rs @@ -1,52 +1,52 @@ pub mod big_types { - macro_rules! big_types_modules { - ($bits: literal) => { - pub mod u8 { - pub type UTEST = crate::BUintD8<{$bits / 8}>; - pub type ITEST = crate::BIntD8<{$bits / 8}>; - } - pub mod u16 { - pub type UTEST = crate::BUintD16<{$bits / 16}>; - pub type ITEST = crate::BIntD16<{$bits / 16}>; - } - pub mod u32 { - pub type UTEST = crate::BUintD32<{$bits / 32}>; - pub type ITEST = crate::BIntD32<{$bits / 32}>; - } - pub mod u64 { - pub type UTEST = crate::BUint<{$bits / 64}>; - pub type ITEST = crate::BInt<{$bits / 64}>; - } - } - } + macro_rules! big_types_modules { + ($bits: literal) => { + pub mod u8 { + pub type UTEST = crate::BUintD8<{ $bits / 8 }>; + pub type ITEST = crate::BIntD8<{ $bits / 8 }>; + } + pub mod u16 { + pub type UTEST = crate::BUintD16<{ $bits / 16 }>; + pub type ITEST = crate::BIntD16<{ $bits / 16 }>; + } + pub mod u32 { + pub type UTEST = crate::BUintD32<{ $bits / 32 }>; + pub type ITEST = crate::BIntD32<{ $bits / 32 }>; + } + pub mod u64 { + pub type UTEST = crate::BUint<{ $bits / 64 }>; + pub type ITEST = crate::BInt<{ $bits / 64 }>; + } + }; + } - #[cfg(test_int_bits = "64")] - big_types_modules!(64); + #[cfg(test_int_bits = "64")] + big_types_modules!(64); - #[cfg(not(test_int_bits = "64"))] - big_types_modules!(128); + #[cfg(not(test_int_bits = "64"))] + big_types_modules!(128); } #[cfg(test_int_bits = "64")] mod small_types { - #[allow(non_camel_case_types)] - pub type utest = u64; + #[allow(non_camel_case_types)] + pub type utest = u64; - #[allow(non_camel_case_types)] - pub type itest = i64; + #[allow(non_camel_case_types)] + pub type itest = i64; } #[cfg(not(test_int_bits = "64"))] mod small_types { - #[allow(non_camel_case_types)] - pub type utest = u128; + #[allow(non_camel_case_types)] + pub type utest = u128; - #[allow(non_camel_case_types)] - pub type itest = i128; + #[allow(non_camel_case_types)] + pub type itest = i128; } -pub use small_types::*; pub use core::primitive::*; +pub use small_types::*; /*#[cfg(test_int_bits = "64")] #[allow(non_camel_case_types)] @@ -62,4 +62,4 @@ pub type FTEST = crate::float::Float<8, 52>; #[cfg(feature = "nightly")] #[cfg(not(test_int_bits = "64"))] -pub type FTEST = crate::float::Float<4, 23>;*/ \ No newline at end of file +pub type FTEST = crate::float::Float<4, 23>;*/ diff --git a/src/types.rs b/src/types.rs index f9823fc..929cc39 100644 --- a/src/types.rs +++ b/src/types.rs @@ -9,48 +9,48 @@ macro_rules! int_type_doc { } macro_rules! int_types { - { $($bits: literal $u: ident $i: ident; ) *} => { - $( - #[doc = int_type_doc!($bits, "unsigned")] - pub type $u = BUint::<{$bits / 64}>; - - #[doc = int_type_doc!($bits, "signed")] - pub type $i = BInt::<{$bits / 64}>; - )* - }; + { $($bits: literal $u: ident $i: ident; ) *} => { + $( + #[doc = int_type_doc!($bits, "unsigned")] + pub type $u = BUint::<{$bits / 64}>; + + #[doc = int_type_doc!($bits, "signed")] + pub type $i = BInt::<{$bits / 64}>; + )* + }; } macro_rules! call_types_macro { - ($name: ident) => { - $name! { - 128 U128 I128; - 256 U256 I256; - 512 U512 I512; - 1024 U1024 I1024; - 2048 U2048 I2048; - 4096 U4096 I4096; - 8192 U8192 I8192; - } - } + ($name: ident) => { + $name! { + 128 U128 I128; + 256 U256 I256; + 512 U512 I512; + 1024 U1024 I1024; + 2048 U2048 I2048; + 4096 U4096 I4096; + 8192 U8192 I8192; + } + }; } call_types_macro!(int_types); #[cfg(test)] mod tests { - use super::*; - - macro_rules! assert_int_bits { - { $($bits: literal $u: ident $i: ident; ) *} => { - $( - assert_eq!($u::BITS, $bits); - assert_eq!($i::BITS, $bits); - )* - } - } - - #[test] - fn test_int_bits() { - call_types_macro!(assert_int_bits); - } -} \ No newline at end of file + use super::*; + + macro_rules! assert_int_bits { + { $($bits: literal $u: ident $i: ident; ) *} => { + $( + assert_eq!($u::BITS, $bits); + assert_eq!($i::BITS, $bits); + )* + } + } + + #[test] + fn test_int_bits() { + call_types_macro!(assert_int_bits); + } +}