From 57801c68f33d71f969a272a19e50973129eca1be Mon Sep 17 00:00:00 2001 From: Isaac Holt Date: Mon, 6 Jan 2025 18:03:54 +0000 Subject: [PATCH] get rid of macros --- src/bint/bigint_helpers.rs | 18 +- src/bint/cast.rs | 175 ++--- src/bint/checked.rs | 308 ++++---- src/bint/cmp.rs | 65 +- src/bint/const_trait_fillers.rs | 147 ++-- src/bint/consts.rs | 67 +- src/bint/convert.rs | 117 ++- src/bint/endian.rs | 411 +++++------ src/bint/fmt.rs | 77 +- src/bint/mod.rs | 673 ++++++++--------- src/bint/numtraits.rs | 448 ++++++------ src/bint/ops.rs | 155 ++-- src/bint/overflowing.rs | 480 ++++++------- src/bint/radix.rs | 327 +++++---- src/bint/saturating.rs | 209 +++--- src/bint/strict.rs | 80 +-- src/bint/unchecked.rs | 14 +- src/bint/wrapping.rs | 213 +++--- src/buint/bigint_helpers.rs | 107 ++- src/buint/cast.rs | 283 ++++---- src/buint/checked.rs | 474 ++++++------ src/buint/cmp.rs | 56 +- src/buint/const_trait_fillers.rs | 172 +++-- src/buint/consts.rs | 36 +- src/buint/convert.rs | 114 ++- src/buint/div.rs | 371 +++++----- src/buint/endian.rs | 539 +++++++------- src/buint/fmt.rs | 171 +++-- src/buint/mask.rs | 12 +- src/buint/mod.rs | 1119 ++++++++++++++--------------- src/buint/mul.rs | 71 +- src/buint/numtraits.rs | 672 ++++++++--------- src/buint/ops.rs | 205 +++--- src/buint/overflowing.rs | 268 ++++--- src/buint/radix.rs | 1020 +++++++++++++------------- src/buint/saturating.rs | 126 ++-- src/buint/strict.rs | 35 +- src/buint/unchecked.rs | 13 +- src/buint/wrapping.rs | 204 +++--- src/cast/float/float_from_uint.rs | 16 +- src/cast/float/mod.rs | 117 ++- src/cast/float/uint_from_float.rs | 8 +- src/cast/mod.rs | 2 +- src/digit.rs | 237 +++--- src/doc/consts.rs | 2 +- src/errors/macros.rs | 12 +- src/errors/parseint.rs | 3 +- src/float/cast.rs | 14 +- src/helpers.rs | 46 +- src/int/cast.rs | 2 +- src/int/checked.rs | 1 + src/int/numtraits.rs | 18 +- src/int/ops.rs | 41 +- src/int/strict.rs | 9 +- src/int/unchecked.rs | 4 +- src/lib.rs | 54 +- src/prelude.rs | 4 +- src/random.rs | 47 +- src/test/convert.rs | 22 +- src/test/macros.rs | 32 +- src/test/mod.rs | 29 +- src/test/types.rs | 99 +-- src/types.rs | 6 +- 63 files changed, 5298 insertions(+), 5579 deletions(-) diff --git a/src/bint/bigint_helpers.rs b/src/bint/bigint_helpers.rs index aad91d4..8eb22b4 100644 --- a/src/bint/bigint_helpers.rs +++ b/src/bint/bigint_helpers.rs @@ -1,19 +1,15 @@ -macro_rules! bigint_helpers { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::bigint_helpers::impl_desc!()] - impl $BInt { - crate::int::bigint_helpers::impls!(I); - } - }; +use super::BIntD8; + +#[doc = doc::bigint_helpers::impl_desc!()] +impl BIntD8 { + crate::int::bigint_helpers::impls!(I); } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::types::itest; - + crate::int::bigint_helpers::tests!(itest); } use crate::doc; - -crate::macro_impl!(bigint_helpers); diff --git a/src/bint/cast.rs b/src/bint/cast.rs index 7bbc129..93cec7f 100644 --- a/src/bint/cast.rs +++ b/src/bint/cast.rs @@ -1,15 +1,18 @@ +use super::BIntD8; +use crate::{BUintD8, digit, Digit}; + macro_rules! bint_as { - ($BInt: ident, $Digit: ident; $($int: ty), *) => { + ($($int: ty), *) => { $( - impl CastFrom<$BInt> for $int { + impl CastFrom> for $int { #[inline] - fn cast_from(from: $BInt) -> Self { + fn cast_from(from: BIntD8) -> 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)); + while i << digit::BIT_SHIFT < <$int>::BITS as usize && i < N { + out &= !((!digits[i]) as $int << (i << digit::BIT_SHIFT)); i += 1; } out @@ -23,12 +26,12 @@ macro_rules! bint_as { } macro_rules! as_bint { - ($BInt: ident, $BUint: ident; $($ty: ty), *) => { + ($($ty: ty), *) => { $( - impl CastFrom<$ty> for $BInt { + impl CastFrom<$ty> for BIntD8 { #[inline] fn cast_from(from: $ty) -> Self { - Self::from_bits($BUint::cast_from(from)) + Self::from_bits(BUintD8::cast_from(from)) } } )* @@ -36,18 +39,18 @@ macro_rules! as_bint { } macro_rules! bint_cast_from_float { - ($f: ty, $BUint: ident <$N: ident>) => { + ($f: ty) => { #[inline] fn cast_from(from: $f) -> Self { if from.is_sign_negative() { - let u = $BUint::<$N>::cast_from(-from); + let u = BUintD8::::cast_from(-from); if u >= Self::MIN.to_bits() { Self::MIN } else { -Self::from_bits(u) } } else { - let u = $BUint::<$N>::cast_from(from); + let u = BUintD8::::cast_from(from); let i = Self::from_bits(u); if i.is_negative() { Self::MAX @@ -62,130 +65,60 @@ macro_rules! bint_cast_from_float { pub(crate) use bint_cast_from_float; use crate::cast::CastFrom; -use crate::digit; -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); +bint_as!(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> for f32 { + #[inline] + fn cast_from(from: BIntD8) -> 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> for f64 { + #[inline] + fn cast_from(from: BIntD8) -> 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!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool, char); - impl CastFrom<$BUint> for $BInt { - #[inline] - fn cast_from(from: $BUint) -> Self { - Self::from_bits($BUint::cast_from(from)) - } - } +impl CastFrom> for BIntD8 { + #[inline] + fn cast_from(from: BUintD8) -> Self { + Self::from_bits(BUintD8::cast_from(from)) + } +} - impl CastFrom<$BInt> for $BInt { - #[inline] - fn cast_from(from: $BInt) -> Self { - Self::from_bits($BUint::cast_from(from)) - } - } +impl CastFrom> for BIntD8 { + #[inline] + fn cast_from(from: BIntD8) -> Self { + Self::from_bits(BUintD8::cast_from(from)) + } +} - impl CastFrom for $BInt { - crate::bint::cast::bint_cast_from_float!(f32, $BUint); - } +impl CastFrom for BIntD8 { + crate::bint::cast::bint_cast_from_float!(f32); +} - impl CastFrom for $BInt { - crate::bint::cast::bint_cast_from_float!(f64, $BUint); - } - }; +impl CastFrom for BIntD8 { + crate::bint::cast::bint_cast_from_float!(f64); } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::types::itest; crate::int::cast::tests!(itest); } - -crate::macro_impl!(cast); - -macro_rules! bint_as_different_digit_bigint { - ($BUint: ident, $BInt: ident, $Digit: ident; $(($OtherBInt: ident, $OtherDigit: ident)), *) => { - $( - impl crate::cast::CastFrom<$OtherBInt> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $OtherBInt) -> Self { - if !from.is_negative() || M * $OtherDigit::BITS as usize >= N * $Digit::BITS as usize { // $OtherBInt::BITS <= $Int::BITS - Self::cast_from(from.to_bits()) - } else { - let mut out = Self::MAX; - if $Digit::BITS < $OtherDigit::BITS { - const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize; - let stop_index: usize = if <$OtherBInt>::BITS > <$BUint>::BITS { - N - } else { - M * DIVIDE_COUNT - }; - let mut i = 0; - while i < stop_index { - let wider_digit = from.bits.digits[i / DIVIDE_COUNT]; - let mini_shift = i % DIVIDE_COUNT; - let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit; - out.digits[i] = digit; - i += 1; - } - } else { - const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize; - let stop_index: usize = if <$OtherBInt>::BITS > <$BUint>::BITS { - N * DIVIDE_COUNT - } else { - M - }; - let mut current_digit: $Digit = $Digit::MAX; - let mut i = 0; - while i < stop_index { - let mini_shift = i % DIVIDE_COUNT; - current_digit &= !((!from.bits.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT)); - if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 { - out.digits[i / DIVIDE_COUNT] = current_digit; - current_digit = $Digit::MAX; - } - i += 1; - } - } - out - } - } - } - - impl crate::cast::CastFrom<$OtherBInt> for $BInt { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $OtherBInt) -> Self { - Self::from_bits($BUint::::cast_from(from)) - } - } - )* - }; -} - -pub(crate) use bint_as_different_digit_bigint; \ No newline at end of file diff --git a/src/bint/checked.rs b/src/bint/checked.rs index 050e3e1..76b6afc 100644 --- a/src/bint/checked.rs +++ b/src/bint/checked.rs @@ -1,3 +1,6 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + macro_rules! checked_ilog { ($method: ident $(, $base: ident: $ty: ty)?) => { #[doc = doc::checked::$method!(I)] @@ -17,184 +20,179 @@ use crate::doc; use crate::helpers::tuple_to_option; use crate::ExpType; -macro_rules! checked { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::checked::impl_desc!()] - impl $BInt { - #[doc = doc::checked::checked_add!(I)] - #[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::impl_desc!()] +impl BIntD8 { + #[doc = doc::checked::checked_add!(I)] + #[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_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_add_unsigned(self, rhs: $BUint) -> Option { - tuple_to_option(self.overflowing_add_unsigned(rhs)) - } + #[doc = doc::checked::checked_add_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_add_unsigned(self, rhs: BUintD8) -> Option { + tuple_to_option(self.overflowing_add_unsigned(rhs)) + } - #[doc = doc::checked::checked_sub!(I)] - #[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_sub!(I)] + #[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_sub_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_sub_unsigned(self, rhs: $BUint) -> Option { - tuple_to_option(self.overflowing_sub_unsigned(rhs)) - } + #[doc = doc::checked::checked_sub_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_sub_unsigned(self, rhs: BUintD8) -> Option { + 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)) - } + #[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)) + } - #[doc = doc::checked::checked_div!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if rhs.is_zero() { - None - } else { - tuple_to_option(self.overflowing_div(rhs)) - } - } + #[doc = doc::checked::checked_div!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if rhs.is_zero() { + None + } else { + tuple_to_option(self.overflowing_div(rhs)) + } + } - #[doc = doc::checked::checked_div_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if rhs.is_zero() { - None - } else { - tuple_to_option(self.overflowing_div_euclid(rhs)) - } - } + #[doc = doc::checked::checked_div_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if rhs.is_zero() { + None + } else { + tuple_to_option(self.overflowing_div_euclid(rhs)) + } + } - #[doc = doc::checked::checked_rem!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if rhs.is_zero() { - None - } else { - tuple_to_option(self.overflowing_rem(rhs)) - } - } + #[doc = doc::checked::checked_rem!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if rhs.is_zero() { + None + } else { + tuple_to_option(self.overflowing_rem(rhs)) + } + } - #[doc = doc::checked::checked_rem_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if rhs.is_zero() { - None - } else { - tuple_to_option(self.overflowing_rem_euclid(rhs)) - } - } + #[doc = doc::checked::checked_rem_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if rhs.is_zero() { + None + } else { + 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()) + } - #[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) - } - } + #[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) } - None => None, - } - } - - #[doc = doc::checked::checked_next_multiple_of!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { - if rhs.is_zero() { - return None; - } - let rem = self.wrapping_rem_euclid(rhs); - if rem.is_zero() { - return Some(self); - } - if rem.is_negative() == rhs.is_negative() { - self.checked_add(rhs.wrapping_sub(rem)) } else { - self.checked_sub(rem) + let out = out.wrapping_neg(); + if !out.is_negative() { + None + } else { + Some(out) + } } } + None => None, + } + } - #[doc = doc::checked::checked_ilog!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_ilog(self, base: Self) -> Option { - if base.is_negative() || self.is_negative() { - None - } else { - self.to_bits().checked_ilog(base.to_bits()) - } - } + #[doc = doc::checked::checked_next_multiple_of!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { + if rhs.is_zero() { + return None; + } + let rem = self.wrapping_rem_euclid(rhs); + if rem.is_zero() { + return Some(self); + } + if rem.is_negative() == rhs.is_negative() { + self.checked_add(rhs.wrapping_sub(rem)) + } else { + self.checked_sub(rem) + } + } - checked_ilog!(checked_ilog2); - checked_ilog!(checked_ilog10); + #[doc = doc::checked::checked_ilog!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_ilog(self, base: Self) -> Option { + if base.is_negative() || self.is_negative() { + None + } else { + self.to_bits().checked_ilog(base.to_bits()) } - }; -} + } + checked_ilog!(checked_ilog2); + checked_ilog!(checked_ilog10); +} #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::test_bignum; - use crate::test::types::{itest, utest}; + use crate::test::types::*; test_bignum! { function: ::checked_add(a: itest, b: itest), @@ -280,5 +278,3 @@ crate::test::all_digit_tests! { function: ::checked_ilog(a: itest, b: itest) } } - -crate::macro_impl!(checked); diff --git a/src/bint/cmp.rs b/src/bint/cmp.rs index 4b304e6..7653af5 100644 --- a/src/bint/cmp.rs +++ b/src/bint/cmp.rs @@ -1,43 +1,40 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + use core::cmp::{Ord, Ordering, PartialOrd}; -macro_rules! cmp { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl PartialOrd for $BInt { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - impl Ord for $BInt { - #[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) - } - } - }; +impl PartialOrd for BIntD8 { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for BIntD8 { + #[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)] -crate::test::all_digit_tests! { +mod tests { use crate::test::types::*; crate::int::cmp::tests!(itest); } - -crate::macro_impl!(cmp); diff --git a/src/bint/const_trait_fillers.rs b/src/bint/const_trait_fillers.rs index 8654669..b5a41e8 100644 --- a/src/bint/const_trait_fillers.rs +++ b/src/bint/const_trait_fillers.rs @@ -1,94 +1,93 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + 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)) - } +#[doc = doc::const_trait_fillers::impl_desc!()] +impl BIntD8 { + #[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 { + BUintD8::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 { + BUintD8::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 self.strict_neg(); + crate::int::cmp::impls!(); + #[inline] + pub const fn neg(self) -> Self { + #[cfg(debug_assertions)] + return self.strict_neg(); - #[cfg(not(debug_assertions))] - self.wrapping_neg() - } + #[cfg(not(debug_assertions))] + self.wrapping_neg() + } - crate::int::ops::trait_fillers!(); + crate::int::ops::trait_fillers!(); - #[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 - } + #[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 + } + } - #[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 - } + #[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); diff --git a/src/bint/consts.rs b/src/bint/consts.rs index 0bba14d..2fb7a98 100644 --- a/src/bint/consts.rs +++ b/src/bint/consts.rs @@ -1,18 +1,21 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + macro_rules! pos_const { - ($BUint: ident; $($name: ident $num: literal), *) => { + ($($name: ident $num: literal), *) => { $( #[doc = doc::consts::value_desc!($num)] - pub const $name: Self = Self::from_bits($BUint::$name); + pub const $name: Self = Self::from_bits(BUintD8::$name); )* } } macro_rules! neg_const { - ($BUint: ident; $($name: ident $num: literal), *) => { + ($($name: ident $num: literal), *) => { $( #[doc = doc::consts::value_desc!("-" $num)] pub const $name: Self = { - let mut u = $BUint::MAX; + let mut u = BUintD8::MAX; u.digits[0] -= ($num - 1); Self::from_bits(u) }; @@ -23,43 +26,37 @@ macro_rules! neg_const { 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)) - }; +#[doc = doc::consts::impl_desc!()] +impl BIntD8 { + #[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(BUintD8::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(BUintD8::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 = BUintD8::::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 = BUintD8::::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(BUintD8::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(BUintD8::ONE); - pos_const!($BUint; TWO 2, THREE 3, FOUR 4, FIVE 5, SIX 6, SEVEN 7, EIGHT 8, NINE 9, TEN 10); + pos_const!(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!(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 55530da..c50cd67 100644 --- a/src/bint/convert.rs +++ b/src/bint/convert.rs @@ -1,7 +1,10 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + macro_rules! from_int { - ($BInt: ident, $Digit: ident; $($int: tt),*) => { + ($($int: tt),*) => { $( - impl From<$int> for $BInt { + impl From<$int> for BIntD8 { #[inline] fn from(int: $int) -> Self { let mut out = if int.is_negative() { @@ -10,8 +13,8 @@ macro_rules! from_int { 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; + while i << crate::digit::BIT_SHIFT < $int::BITS as usize { + let d = (int >> (i << crate::digit::BIT_SHIFT)) as Digit; out.bits.digits[i] = d; i += 1; } @@ -23,12 +26,12 @@ macro_rules! from_int { } macro_rules! from_uint { - ($BInt: ident, $BUint: ident; $($from: tt), *) => { + ($($from: tt), *) => { $( - impl From<$from> for $BInt { + impl From<$from> for BIntD8 { #[inline] fn from(int: $from) -> Self { - let out = Self::from_bits($BUint::from(int)); + let out = Self::from_bits(BUintD8::from(int)); out } } @@ -37,22 +40,22 @@ macro_rules! from_uint { } macro_rules! int_try_from_bint { - { $BInt: ident, $Digit: ident; $($int: ty), * } => { + { $($int: ty), * } => { $( - impl TryFrom<$BInt> for $int { + impl TryFrom> for $int { type Error = TryFromIntError; - fn try_from(int: $BInt) -> Result<$int, Self::Error> { + fn try_from(int: BIntD8) -> Result<$int, Self::Error> { let neg = int.is_negative(); let (mut out, padding) = if neg { - (-1, $Digit::MAX) + (-1, Digit::MAX) } else { - (0, $Digit::MIN) + (0, Digit::MIN) }; let mut i = 0; - if $Digit::BITS > <$int>::BITS { + if Digit::BITS > <$int>::BITS { let small = int.bits.digits[i] as $int; - let trunc = small as $Digit; + let trunc = small as Digit; if int.bits.digits[i] != trunc { return Err(TryFromIntError(())); } @@ -61,7 +64,7 @@ macro_rules! int_try_from_bint { } else { if neg { loop { - let shift = i << digit::$Digit::BIT_SHIFT; + let shift = i << digit::BIT_SHIFT; if i >= N || shift >= <$int>::BITS as usize { break; } @@ -70,7 +73,7 @@ macro_rules! int_try_from_bint { } } else { loop { - let shift = i << digit::$Digit::BIT_SHIFT; + let shift = i << digit::BIT_SHIFT; if i >= N || shift >= <$int>::BITS as usize { break; } @@ -99,13 +102,13 @@ macro_rules! int_try_from_bint { } macro_rules! uint_try_from_bint { - ($BInt: ident; $($uint: ty), *) => { + ($($uint: ty), *) => { $( - impl TryFrom<$BInt> for $uint { + impl TryFrom> for $uint { type Error = TryFromIntError; #[inline] - fn try_from(int: $BInt) -> Result<$uint, Self::Error> { + fn try_from(int: BIntD8) -> Result<$uint, Self::Error> { if int.is_negative() { Err(TryFromIntError(())) } else { @@ -122,55 +125,51 @@ use crate::digit; use crate::errors::{ParseIntError, TryFromIntError}; use core::str::FromStr; -macro_rules! convert { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl FromStr for $BInt { - type Err = ParseIntError; +impl FromStr for BIntD8 { + type Err = ParseIntError; - #[inline] - fn from_str(src: &str) -> Result { - Self::from_str_radix(src, 10) - } - } + #[inline] + fn from_str(src: &str) -> Result { + Self::from_str_radix(src, 10) + } +} - from_int!($BInt, $Digit; i8, i16, i32, i64, i128, isize); +from_int!(i8, i16, i32, i64, i128, isize); - from_uint!($BInt, $BUint; u8, u16, u32, u64, u128, usize); +from_uint!(u8, u16, u32, u64, u128, usize); - impl 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)) - // } - // } - // } - // } - }; +impl From for BIntD8 { + #[inline] + fn from(small: bool) -> Self { + Self::cast_from(small) + } } +int_try_from_bint!(i8, i16, i32, i64, i128, isize); +uint_try_from_bint!(u8, u16, u32, u64, u128, usize); + +// impl_const! { +// impl const TryFrom> for BIntD8 { +// type Error = TryFromIntError; + +// #[inline] +// fn try_from(u: BUintD8) -> Result { +// if u.leading_ones() != 0 { +// Err(TryFromIntError(())) +// } else { +// Ok(Self::from_bits(u)) +// } +// } +// } +// } + #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test; - use crate::test::types::itest; + use crate::test::types::*; use crate::test::cast_types::*; use crate::BTryFrom; - + test::test_btryfrom!(itest; TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10); #[cfg(test_int_bits = "128")] @@ -190,5 +189,3 @@ crate::test::all_digit_tests! { into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize) } } - -crate::macro_impl!(convert); diff --git a/src/bint/endian.rs b/src/bint/endian.rs index 7d37548..16180ca 100644 --- a/src/bint/endian.rs +++ b/src/bint/endian.rs @@ -1,232 +1,217 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + use crate::digit; 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) - } - - /// 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 mut i = 0; - let exact = len >> digit::$Digit::BYTE_SHIFT; - while i < exact { - let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize]; - let init_index = len - digit::$Digit::BYTES as usize; - let mut j = init_index; - while j < slice.len() { - digit_bytes[j - init_index] = slice[j - (i << digit::$Digit::BYTE_SHIFT)]; - j += 1; - } - 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 digit_bytes = [0u8; digit::$Digit::BYTES as usize]; - let init_index = i << digit::$Digit::BYTE_SHIFT; - let mut j = init_index; - while j < init_index + digit::$Digit::BYTES as usize { - digit_bytes[j - init_index] = slice[j]; - j += 1; - } - - 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; $BUint::::BYTES_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; $BUint::::BYTES_USIZE] { - self.bits.to_le_bytes() +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::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; + }; + }; +} - #[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; $BUint::::BYTES_USIZE] { - self.bits.to_ne_bytes() +#[doc = doc::endian::impl_desc!(BIntD8)] +impl BIntD8 { + #[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(BUintD8::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(BUintD8::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!(BUintD8), "::from_be_slice)")] + /// method documentation for + #[doc = concat!("[`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ").")] + #[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 mut i = 0; + let exact = len >> digit::BYTE_SHIFT; + while i < exact { + let mut digit_bytes = [0u8; digit::BYTES as usize]; + let init_index = len - digit::BYTES as usize; + let mut j = init_index; + while j < slice.len() { + digit_bytes[j - init_index] = slice[j - (i << digit::BYTE_SHIFT)]; + j += 1; } - - #[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; $BUint::::BYTES_USIZE]) -> Self { - Self::from_bits($BUint::from_be_bytes(bytes)) + let digit = Digit::from_be_bytes(digit_bytes); + set_digit!(out_digits, i, digit, is_negative, sign_bits); + i += 1; + } + let rem = len & (digit::BYTES as usize - 1); + if rem == 0 { + Some(Self::from_bits(BUintD8::from_digits(out_digits))) + } else { + let pad_byte = if is_negative { u8::MAX } else { 0 }; + let mut last_digit_bytes = [pad_byte; digit::BYTES as usize]; + let mut j = 0; + while j < rem { + last_digit_bytes[digit::BYTES as usize - rem + j] = slice[j]; + j += 1; } - - #[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; $BUint::::BYTES_USIZE]) -> Self { - Self::from_bits($BUint::from_le_bytes(bytes)) + let digit = Digit::from_be_bytes(last_digit_bytes); + set_digit!(out_digits, i, digit, is_negative, sign_bits); + Some(Self::from_bits(BUintD8::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!(BUintD8), "::from_le_slice)")] + /// method documentation for + #[doc = concat!("[`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ").")] + #[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::BYTE_SHIFT; + while i < exact { + let mut digit_bytes = [0u8; digit::BYTES as usize]; + let init_index = i << digit::BYTE_SHIFT; + let mut j = init_index; + while j < init_index + digit::BYTES as usize { + digit_bytes[j - init_index] = slice[j]; + j += 1; } - #[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; $BUint::::BYTES_USIZE]) -> Self { - Self::from_bits($BUint::from_ne_bytes(bytes)) + let digit = Digit::from_le_bytes(digit_bytes); + set_digit!(out_digits, i, digit, is_negative, sign_bits); + i += 1; + } + if len & (digit::BYTES as usize - 1) == 0 { + Some(Self::from_bits(BUintD8::from_digits(out_digits))) + } else { + let pad_byte = if is_negative { u8::MAX } else { 0 }; + let mut last_digit_bytes = [pad_byte; digit::BYTES as usize]; + let addition = exact << 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(BUintD8::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; BUintD8::::BYTES_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; BUintD8::::BYTES_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; BUintD8::::BYTES_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; BUintD8::::BYTES_USIZE]) -> Self { + Self::from_bits(BUintD8::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; BUintD8::::BYTES_USIZE]) -> Self { + Self::from_bits(BUintD8::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; BUintD8::::BYTES_USIZE]) -> Self { + Self::from_bits(BUintD8::from_ne_bytes(bytes)) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::test_bignum; - use crate::test::types::itest; + use crate::test::types::*; crate::int::endian::tests!(itest); } - -crate::macro_impl!(endian); diff --git a/src/bint/fmt.rs b/src/bint/fmt.rs index 0138b2f..b1cf1c0 100644 --- a/src/bint/fmt.rs +++ b/src/bint/fmt.rs @@ -1,8 +1,11 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + use core::fmt::{Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, UpperExp, UpperHex}; macro_rules! fmt_trait { - ($BInt: ident, $trait: tt) => { - impl $trait for $BInt { + ($trait: tt) => { + impl $trait for BIntD8 { #[inline] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { $trait::fmt(&self.bits, f) @@ -11,49 +14,43 @@ macro_rules! fmt_trait { }; } -macro_rules! fmt { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - fmt_trait!($BInt, Binary); - - impl Display for $BInt { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - f.pad_integral(!self.is_negative(), "", &format!("{}", self.unsigned_abs())) - } - } +fmt_trait!(Binary); - impl Debug for $BInt { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - Display::fmt(&self, f) - } - } +impl Display for BIntD8 { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + f.pad_integral(!self.is_negative(), "", &format!("{}", self.unsigned_abs())) + } +} - impl LowerExp for $BInt { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - let uint = self.unsigned_abs(); - f.pad_integral(!self.is_negative(), "", &format!("{:e}", uint)) - } - } - fmt_trait!($BInt, LowerHex); - fmt_trait!($BInt, Octal); +impl Debug for BIntD8 { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + Display::fmt(&self, f) + } +} - impl UpperExp for $BInt { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - let uint = self.unsigned_abs(); - f.pad_integral(!self.is_negative(), "", &format!("{:E}", uint)) - } - } - - fmt_trait!($BInt, UpperHex); - }; +impl LowerExp for BIntD8 { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + let uint = self.unsigned_abs(); + f.pad_integral(!self.is_negative(), "", &format!("{:e}", uint)) + } } +fmt_trait!(LowerHex); +fmt_trait!(Octal); + +impl UpperExp for BIntD8 { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + let uint = self.unsigned_abs(); + f.pad_integral(!self.is_negative(), "", &format!("{:E}", uint)) + } +} + +fmt_trait!(UpperHex); #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { crate::int::fmt::tests!(itest); } - -crate::macro_impl!(fmt); diff --git a/src/bint/mod.rs b/src/bint/mod.rs index 5f019c5..9f58467 100644 --- a/src/bint/mod.rs +++ b/src/bint/mod.rs @@ -1,3 +1,5 @@ +use crate::{BUintD8, Digit}; + macro_rules! ilog { ($method: ident $(, $base: ident : $ty: ty)?) => { #[doc = doc::$method!(I)] @@ -35,190 +37,196 @@ use core::default::Default; use core::iter::{Iterator, Product, Sum}; -macro_rules! mod_impl { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - /// Big signed integer type, of fixed size which must be known at compile time. Stored as a - #[doc = concat!(" [`", stringify!($BUint), "`].")] - /// - /// 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)] - - #[derive(Clone, Copy, Hash, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] - #[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize, BorshSchema))] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - #[cfg_attr(feature = "valuable", derive(valuable::Valuable))] - #[repr(transparent)] - pub struct $BInt { - pub(crate) bits: $BUint, - } +/// Big signed integer type, of fixed size which must be known at compile time. Stored as a +#[doc = concat!(" [`", stringify!(BUintD8), "`].")] +/// +/// Digits of the underlying +#[doc = concat!("[`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ")")] +/// 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!(BUintD8), "`].")] +/// +#[doc = doc::arithmetic_doc!(BIntD8)] +#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "borsh", + derive(BorshSerialize, BorshDeserialize, BorshSchema) +)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "valuable", derive(valuable::Valuable))] +#[repr(transparent)] +pub struct BIntD8 { + pub(crate) bits: BUintD8, +} - #[cfg(feature = "zeroize")] - impl zeroize::DefaultIsZeroes for $BInt {} +#[cfg(feature = "zeroize")] +impl zeroize::DefaultIsZeroes for BIntD8 {} - 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() - } +impl BIntD8 { + #[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::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::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::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::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::trailing_ones!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn trailing_ones(self) -> ExpType { + self.bits.trailing_ones() + } - #[doc = doc::cast_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn cast_unsigned(self) -> $BUint { - self.to_bits() - } + #[doc = doc::cast_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn cast_unsigned(self) -> BUintD8 { + self.to_bits() + } - #[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_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::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::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::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::unsigned_abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn unsigned_abs(self) -> BUintD8 { + 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 self.strict_pow(exp); + #[doc = doc::pow!(I 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn pow(self, exp: ExpType) -> Self { + #[cfg(debug_assertions)] + return self.strict_pow(exp); - #[cfg(not(debug_assertions))] - self.wrapping_pow(exp) - } + #[cfg(not(debug_assertions))] + self.wrapping_pow(exp) + } - #[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::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::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 self.strict_abs(); - - #[cfg(not(debug_assertions))] - match self.checked_abs() { - Some(int) => int, - None => Self::MIN, - } - } + #[doc = doc::abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn abs(self) -> Self { + #[cfg(debug_assertions)] + return self.strict_abs(); + + #[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::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_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::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! { + #[doc = doc::doc_comment! { I 256, "Returns `true` if and only if `self == 2^k` for some integer `k`.", @@ -228,201 +236,200 @@ macro_rules! mod_impl { "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() - } + #[must_use] + #[inline] + pub const fn is_power_of_two(self) -> bool { + !self.is_negative() && self.bits.is_power_of_two() + } - #[doc = doc::midpoint!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn midpoint(self, rhs: Self) -> Self { - // see section 2.5: Average of Two Integers in Hacker's Delight - let x = self.bitxor(rhs); - let t = self.bitand(rhs).add(x.shr(1)); - if t.is_negative() && x.bits.digits[0] & 1 == 1 { // t is negative and - t.add($BInt::ONE) - } else { - t - } - } + #[doc = doc::midpoint!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn midpoint(self, rhs: Self) -> Self { + // see section 2.5: Average of Two Integers in Hacker's Delight + let x = self.bitxor(rhs); + let t = self.bitand(rhs).add(x.shr(1)); + if t.is_negative() && x.bits.digits[0] & 1 == 1 { + // t is negative and + t.add(BIntD8::ONE) + } else { + t + } + } - 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() - } - } + 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) -> BUintD8 { + if self.lt(&other) { + other.wrapping_sub(self).to_bits() + } else { + self.wrapping_sub(other).to_bits() + } + } - #[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::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_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) - } - } + #[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() - } +impl BIntD8 { + #[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) - } + #[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 _ - } + #[inline(always)] + pub(crate) const fn signed_digit(&self) -> 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_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() - } + #[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 } - } + /// 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!(BUintD8), "`]")] + /// to a + #[doc = concat!("[`", stringify!(BIntD8), "`]")] + /// of the same size than using the `As` trait. + #[must_use] + #[inline(always)] + pub const fn from_bits(bits: BUintD8) -> 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 - } - } + /// 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!(BIntD8), "`]")] + /// to a + #[doc = concat!("[`", stringify!(BUintD8), "`]")] + /// of the same size than using the `As` trait. + #[must_use] + #[inline(always)] + pub const fn to_bits(self) -> BUintD8 { + self.bits + } +} - impl Default for $BInt { - #[doc = doc::default!()] - #[inline] - fn default() -> Self { - Self::ZERO - } - } +impl Default for BIntD8 { + #[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 Product for BIntD8 { + #[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<'a, const N: usize> Product<&'a Self> for BIntD8 { + #[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 Sum for BIntD8 { + #[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) - } - } +impl<'a, const N: usize> Sum<&'a Self> for BIntD8 { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |a, b| a + b) + } +} - #[cfg(any(test, feature = "quickcheck"))] - impl quickcheck::Arbitrary for $BInt { - #[inline] - fn arbitrary(g: &mut quickcheck::Gen) -> Self { - Self::from_bits(<$BUint:: as quickcheck::Arbitrary>::arbitrary(g)) - } - } - }; +#[cfg(any(test, feature = "quickcheck"))] +impl quickcheck::Arbitrary for BIntD8 { + #[inline] + fn arbitrary(g: &mut quickcheck::Gen) -> Self { + Self::from_bits( as quickcheck::Arbitrary>::arbitrary(g)) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::{ debug_skip, test_bignum, - types::itest, + types::*, }; - // use crate::test::types::big_types::$Digit::*; + // use crate::test::types::big_types::Digit::*; crate::int::tests!(itest); @@ -507,8 +514,6 @@ crate::test::all_digit_tests! { } } -crate::macro_impl!(mod_impl); - mod bigint_helpers; pub mod cast; mod checked; diff --git a/src/bint/numtraits.rs b/src/bint/numtraits.rs index 9114711..341dff5 100644 --- a/src/bint/numtraits.rs +++ b/src/bint/numtraits.rs @@ -1,17 +1,20 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + macro_rules! from_int { - ($BUint: ident, $Digit: ident; $int: ty, $name: ident) => { + ($int: ty, $name: ident) => { #[inline] fn $name(n: $int) -> Option { const INT_BITS: usize = <$int>::BITS as usize; let initial_digit = if n.is_negative() { - $Digit::MAX + Digit::MAX } else { - $Digit::MIN + Digit::MIN }; - let mut out = Self::from_bits($BUint::from_digits([initial_digit; N])); + let mut out = Self::from_bits(BUintD8::from_digits([initial_digit; N])); let mut i = 0; - while i << crate::digit::$Digit::BIT_SHIFT < INT_BITS { - let d = (n >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit; + while i << crate::digit::BIT_SHIFT < INT_BITS { + let d = (n >> (i << crate::digit::BIT_SHIFT)) as Digit; if d != initial_digit { if i < N { out.bits.digits[i] = d; @@ -30,14 +33,14 @@ macro_rules! from_int { } macro_rules! from_uint { - ($Digit: ident; $uint: ty, $name: ident) => { + ($uint: ty, $name: ident) => { #[inline] fn $name(n: $uint) -> Option { 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 = (n >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit; + while i << crate::digit::BIT_SHIFT < UINT_BITS { + let d = (n >> (i << crate::digit::BIT_SHIFT)) as Digit; if d != 0 { if i < N { out.bits.digits[i] = d; @@ -57,11 +60,11 @@ macro_rules! from_uint { } macro_rules! from_float { - ($BUint: ident; $method: ident, $float: ty) => { + ($method: ident, $float: ty) => { #[inline] fn $method(f: $float) -> Option { if f.is_sign_negative() { - let i = Self::from_bits($BUint::$method(-f)?); + let i = Self::from_bits(BUintD8::$method(-f)?); if i == Self::MIN { Some(Self::MIN) } else if i.is_negative() { @@ -70,7 +73,7 @@ macro_rules! from_float { Some(-i) } } else { - let i = Self::from_bits($BUint::$method(f)?); + let i = Self::from_bits(BUintD8::$method(f)?); if i.is_negative() { None } else { @@ -97,19 +100,19 @@ macro_rules! to_uint { } macro_rules! to_int { - { $Digit: ident; $($name: ident -> $int: ty), * } => { + { $($name: ident -> $int: ty), * } => { $( fn $name(&self) -> Option<$int> { let neg = self.is_negative(); let (mut out, padding) = if neg { - (-1, $Digit::MAX) + (-1, Digit::MAX) } else { - (0, $Digit::MIN) + (0, Digit::MIN) }; let mut i = 0; - if $Digit::BITS > <$int>::BITS { + if Digit::BITS > <$int>::BITS { let small = self.bits.digits[i] as $int; - let trunc = small as $Digit; + let trunc = small as Digit; if self.bits.digits[i] != trunc { return None; } @@ -118,7 +121,7 @@ macro_rules! to_int { } else { if neg { loop { - let shift = i << digit::$Digit::BIT_SHIFT; + let shift = i << digit::BIT_SHIFT; if i >= N || shift >= <$int>::BITS as usize { break; } @@ -127,7 +130,7 @@ macro_rules! to_int { } } else { loop { - let shift = i << digit::$Digit::BIT_SHIFT; + let shift = i << digit::BIT_SHIFT; if i >= N || shift >= <$int>::BITS as usize { break; } @@ -159,224 +162,245 @@ use crate::errors; use crate::ExpType; use num_integer::{Integer, Roots}; use num_traits::{ - AsPrimitive, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, - CheckedShr, CheckedSub, CheckedEuclid, Euclid, FromPrimitive, MulAdd, MulAddAssign, Num, One, /*ConstOne,*/ Pow, PrimInt, - Saturating, SaturatingAdd, SaturatingMul, SaturatingSub, Signed, ToPrimitive, WrappingAdd, - WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, Zero, //ConstZero + AsPrimitive, + Bounded, + CheckedAdd, + CheckedDiv, + CheckedEuclid, + CheckedMul, + CheckedNeg, + CheckedRem, + CheckedShl, + CheckedShr, + CheckedSub, + Euclid, + FromPrimitive, + MulAdd, + MulAddAssign, + Num, + One, + /*ConstOne,*/ Pow, + PrimInt, + Saturating, + SaturatingAdd, + SaturatingMul, + SaturatingSub, + Signed, + ToPrimitive, + WrappingAdd, + WrappingMul, + WrappingNeg, + WrappingShl, + WrappingShr, + WrappingSub, + Zero, //ConstZero }; 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, $Digit); - - 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); - } - - 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); - out.abs() - } - - #[inline] - fn lcm(&self, other: &Self) -> Self { - if self.is_zero() || other.is_zero() { - Self::ZERO - } else { - (self.div_floor(&self.gcd(other)) * *other).abs() - } - } - - #[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() - } +crate::int::numtraits::impls!(BIntD8); + +impl FromPrimitive for BIntD8 { + from_uint!(u8, from_u8); + from_uint!(u16, from_u16); + from_uint!(u32, from_u32); + from_uint!(u64, from_u64); + from_uint!(u128, from_u128); + from_uint!(usize, from_usize); + from_int!(i8, from_i8); + from_int!(i16, from_i16); + from_int!(i32, from_i32); + from_int!(i64, from_i64); + from_int!(i128, from_i128); + from_int!(isize, from_isize); + + from_float!(from_f32, f32); + from_float!(from_f64, f64); +} - #[inline] - fn div_rem(&self, other: &Self) -> (Self, Self) { - (self.div_floor(other), self.mod_floor(other)) - } +impl Integer for BIntD8 { + #[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); + out.abs() + } + + #[inline] + fn lcm(&self, other: &Self) -> Self { + if self.is_zero() || other.is_zero() { + Self::ZERO + } else { + (self.div_floor(&self.gcd(other)) * *other).abs() } + } + + #[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)) + } +} - 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 - } +impl PrimInt for BIntD8 { + crate::int::numtraits::prim_int_methods!(); - #[inline] - fn unsigned_shl(self, n: u32) -> Self { - self << n - } + #[inline] + fn signed_shl(self, n: u32) -> Self { + self << n + } - #[inline] - fn unsigned_shr(self, n: u32) -> Self { - Self::from_bits(self.to_bits() >> n) - } - } + #[inline] + fn signed_shr(self, n: u32) -> Self { + self >> 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 unsigned_shl(self, n: u32) -> Self { + self << n + } - #[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 unsigned_shr(self, n: u32) -> Self { + Self::from_bits(self.to_bits() >> n) + } +} - #[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)) - } - } +impl Roots for BIntD8 { + #[inline] + fn sqrt(&self) -> Self { + if self.is_negative() { + panic!(crate::errors::err_msg!("imaginary square root")) + } else { + Self::from_bits(self.bits.sqrt()) } - - 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_()) - } + } + + #[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()) } + } - impl Signed for $BInt { - #[inline] - fn abs(&self) -> Self { - Self::abs(*self) + #[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")); } - - #[inline] - fn abs_sub(&self, other: &Self) -> Self { - if *self <= *other { - Self::ZERO - } else { - *self - *other - } + if n == 1 { + return *self; } - - #[inline] - fn signum(&self) -> Self { - Self::signum(*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)) + } + } +} - #[inline] - fn is_positive(&self) -> bool { - Self::is_positive(*self) - } +impl ToPrimitive for BIntD8 { + to_uint! { + to_u8 -> u8, + to_u16 -> u16, + to_u32 -> u32, + to_u64 -> u64, + to_u128 -> u128, + to_usize -> usize + } + + to_int! { + 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_()) + } +} - #[inline] - fn is_negative(&self) -> bool { - self.signed_digit().is_negative() - } +impl Signed for BIntD8 { + #[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)] -crate::test::all_digit_tests! { - use crate::test::types::itest; +mod tests { + use crate::test::types::*; crate::int::numtraits::tests!(itest); } - -crate::macro_impl!(numtraits); \ No newline at end of file diff --git a/src/bint/ops.rs b/src/bint/ops.rs index 3db2bc4..a8d9313 100644 --- a/src/bint/ops.rs +++ b/src/bint/ops.rs @@ -1,89 +1,88 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + use crate::ExpType; use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, }; -macro_rules! ops { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl Neg for $BInt { - type Output = Self; - - #[inline] - fn neg(self) -> Self { - Self::neg(self) - } - } - - impl Neg for &$BInt { - type Output = $BInt; - - #[inline] - fn neg(self) -> $BInt { - $BInt::neg(*self) - } - } - - impl BitAnd for $BInt { - type Output = Self; - - #[inline] - fn bitand(self, rhs: Self) -> Self { - Self::bitand(self, rhs) - } - } - - impl BitOr for $BInt { - type Output = Self; - - #[inline] - fn bitor(self, rhs: Self) -> Self { - Self::bitor(self, rhs) - } - } - - impl BitXor for $BInt { - type Output = Self; - - #[inline] - fn bitxor(self, rhs: Self) -> Self { - Self::bitxor(self, rhs) - } - } - - impl Div for $BInt { - type Output = Self; - - #[inline] - fn div(self, rhs: Self) -> Self { - Self::div(self, rhs) - } - } - - impl Not for $BInt { - type Output = Self; - - fn not(self) -> Self { - Self::not(self) - } - } - - impl Rem for $BInt { - type Output = Self; - - #[inline] - fn rem(self, rhs: Self) -> Self { - Self::rem(self, rhs) - } - } - - crate::int::ops::impls!($BInt, $BUint, $BInt); - }; +impl Neg for BIntD8 { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + Self::neg(self) + } } +impl Neg for &BIntD8 { + type Output = BIntD8; + + #[inline] + fn neg(self) -> BIntD8 { + BIntD8::neg(*self) + } +} + +impl BitAnd for BIntD8 { + type Output = Self; + + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self::bitand(self, rhs) + } +} + +impl BitOr for BIntD8 { + type Output = Self; + + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self::bitor(self, rhs) + } +} + +impl BitXor for BIntD8 { + type Output = Self; + + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self::bitxor(self, rhs) + } +} + +impl Div for BIntD8 { + type Output = Self; + + #[inline] + fn div(self, rhs: Self) -> Self { + Self::div(self, rhs) + } +} + +impl Not for BIntD8 { + type Output = Self; + + fn not(self) -> Self { + Self::not(self) + } +} + +impl Rem for BIntD8 { + type Output = Self; + + #[inline] + fn rem(self, rhs: Self) -> Self { + Self::rem(self, rhs) + } +} + +crate::int::ops::impls!(BIntD8); + #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::{debug_skip, test_bignum, types::itest}; +mod tests { + use crate::test::{debug_skip, test_bignum, types::*}; use core::ops::Neg; test_bignum! { @@ -91,5 +90,3 @@ crate::test::all_digit_tests! { skip: debug_skip!(a == itest::MIN) } } - -crate::macro_impl!(ops); diff --git a/src/bint/overflowing.rs b/src/bint/overflowing.rs index ba6c21a..f73240a 100644 --- a/src/bint/overflowing.rs +++ b/src/bint/overflowing.rs @@ -1,285 +1,281 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + use crate::digit; use crate::errors::div_zero; use crate::{doc, ExpType}; -macro_rules! overflowing { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::overflowing::impl_desc!()] - impl $BInt { - #[doc = doc::overflowing::overflowing_add!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let mut out = Self::ZERO; - let mut carry = false; +#[doc = doc::overflowing::impl_desc!()] +impl BIntD8 { + #[doc = doc::overflowing::overflowing_add!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let mut out = Self::ZERO; + let mut carry = false; - let self_digits = self.bits.digits; - let rhs_digits = rhs.bits.digits; + let self_digits = self.bits.digits; + let rhs_digits = rhs.bits.digits; - let mut i = 0; - while i < Self::N_MINUS_1 { - let (sum, c) = - digit::$Digit::carrying_add(self_digits[i], rhs_digits[i], carry); - out.bits.digits[i] = sum; - carry = c; - i += 1; - } - let (sum, carry) = digit::$Digit::carrying_add_signed( - self_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit, - rhs_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit, - carry, - ); - out.bits.digits[Self::N_MINUS_1] = sum as $Digit; + let mut i = 0; + while i < Self::N_MINUS_1 { + let (sum, c) = digit::carrying_add(self_digits[i], rhs_digits[i], carry); + out.bits.digits[i] = sum; + carry = c; + i += 1; + } + let (sum, carry) = digit::carrying_add_signed( + self_digits[Self::N_MINUS_1] as digit::SignedDigit, + rhs_digits[Self::N_MINUS_1] as digit::SignedDigit, + carry, + ); + out.bits.digits[Self::N_MINUS_1] = sum as Digit; - (out, carry) - } + (out, carry) + } - #[doc = doc::overflowing::overflowing_add_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_add_unsigned(self, rhs: $BUint) -> (Self, bool) { - let rhs = Self::from_bits(rhs); - let (sum, overflow) = self.overflowing_add(rhs); - (sum, rhs.is_negative() != overflow) - } + #[doc = doc::overflowing::overflowing_add_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_add_unsigned(self, rhs: BUintD8) -> (Self, bool) { + let rhs = Self::from_bits(rhs); + let (sum, overflow) = self.overflowing_add(rhs); + (sum, rhs.is_negative() != overflow) + } - #[doc = doc::overflowing::overflowing_sub!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let mut out = Self::ZERO; - let mut borrow = false; + #[doc = doc::overflowing::overflowing_sub!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let mut out = Self::ZERO; + let mut borrow = false; - let self_digits = self.bits.digits; - let rhs_digits = rhs.bits.digits; + let self_digits = self.bits.digits; + let rhs_digits = rhs.bits.digits; - let mut i = 0; - while i < Self::N_MINUS_1 { - let (sub, b) = - digit::$Digit::borrowing_sub(self_digits[i], rhs_digits[i], borrow); - out.bits.digits[i] = sub; - borrow = b; - i += 1; - } - let (sub, borrow) = digit::$Digit::borrowing_sub_signed( - self_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit, - rhs_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit, - borrow, - ); - out.bits.digits[Self::N_MINUS_1] = sub as $Digit; + let mut i = 0; + while i < Self::N_MINUS_1 { + let (sub, b) = digit::borrowing_sub(self_digits[i], rhs_digits[i], borrow); + out.bits.digits[i] = sub; + borrow = b; + i += 1; + } + let (sub, borrow) = digit::borrowing_sub_signed( + self_digits[Self::N_MINUS_1] as digit::SignedDigit, + rhs_digits[Self::N_MINUS_1] as digit::SignedDigit, + borrow, + ); + out.bits.digits[Self::N_MINUS_1] = sub as Digit; - (out, borrow) - } + (out, borrow) + } - #[doc = doc::overflowing::overflowing_sub_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_sub_unsigned(self, rhs: $BUint) -> (Self, bool) { - let rhs = Self::from_bits(rhs); - let (sum, overflow) = self.overflowing_sub(rhs); - (sum, rhs.is_negative() != overflow) - } + #[doc = doc::overflowing::overflowing_sub_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_sub_unsigned(self, rhs: BUintD8) -> (Self, bool) { + let rhs = Self::from_bits(rhs); + let (sum, overflow) = self.overflowing_sub(rhs); + (sum, rhs.is_negative() != overflow) + } - const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType; + 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), - } - } + #[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), } + } + } - #[inline] - pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) { - if self.eq(&Self::MIN) && rhs.is_one() { - return (self, Self::ZERO); - } - let (div, rem) = self.unsigned_abs().div_rem_unchecked(rhs.unsigned_abs()); - let (div, rem) = (Self::from_bits(div), Self::from_bits(rem)); + #[inline] + pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) { + if self.eq(&Self::MIN) && rhs.is_one() { + return (self, Self::ZERO); + } + let (div, rem) = self.unsigned_abs().div_rem_unchecked(rhs.unsigned_abs()); + let (div, rem) = (Self::from_bits(div), Self::from_bits(rem)); - match (self.is_negative(), rhs.is_negative()) { - (false, false) => (div, rem), - (false, true) => (div.neg(), rem), - (true, false) => (div.neg(), rem.neg()), - (true, true) => (div, rem.neg()), - } - } + match (self.is_negative(), rhs.is_negative()) { + (false, false) => (div, rem), + (false, true) => (div.neg(), rem), + (true, false) => (div.neg(), rem.neg()), + (true, true) => (div, rem.neg()), + } + } - #[doc = doc::overflowing::overflowing_div!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if rhs.is_zero() { - div_zero!() - } - if self.eq(&Self::MIN) { - if rhs.eq(&Self::NEG_ONE) { - return (self, true); - } else if rhs.is_one() { - return (self, false); - } - } - (self.div_rem_unchecked(rhs).0, false) + #[doc = doc::overflowing::overflowing_div!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + if rhs.is_zero() { + div_zero!() + } + if self.eq(&Self::MIN) { + if rhs.eq(&Self::NEG_ONE) { + return (self, true); + } else if rhs.is_one() { + return (self, false); } + } + (self.div_rem_unchecked(rhs).0, false) + } - #[doc = doc::overflowing::overflowing_div_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - if rhs.is_zero() { - div_zero!() - } - if self.eq(&Self::MIN) { - if rhs.eq(&Self::NEG_ONE) { - return (self, true); - } else if rhs.is_one() { - return (self, false); - } - } - let (div, rem) = self.div_rem_unchecked(rhs); - if self.is_negative() { - let r_neg = rhs.is_negative(); - if !rem.is_zero() { - if r_neg { - return (div.add(Self::ONE), false) - } else { - return (div.sub(Self::ONE), false) - }; - } - } - (div, false) + #[doc = doc::overflowing::overflowing_div_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + if rhs.is_zero() { + div_zero!() + } + if self.eq(&Self::MIN) { + if rhs.eq(&Self::NEG_ONE) { + return (self, true); + } else if rhs.is_one() { + return (self, false); } - - #[doc = doc::overflowing::overflowing_rem!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if rhs.is_zero() { - div_zero!() - } - if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { - (Self::ZERO, true) + } + let (div, rem) = self.div_rem_unchecked(rhs); + if self.is_negative() { + let r_neg = rhs.is_negative(); + if !rem.is_zero() { + if r_neg { + return (div.add(Self::ONE), false); } else { - (self.div_rem_unchecked(rhs).1, false) - } + return (div.sub(Self::ONE), false); + }; } + } + (div, false) + } - #[doc = doc::overflowing::overflowing_rem_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if rhs.is_zero() { - div_zero!() - } - if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { - (Self::ZERO, true) + #[doc = doc::overflowing::overflowing_rem!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + if rhs.is_zero() { + div_zero!() + } + if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { + (Self::ZERO, true) + } else { + (self.div_rem_unchecked(rhs).1, false) + } + } + + #[doc = doc::overflowing::overflowing_rem_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + if rhs.is_zero() { + div_zero!() + } + if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) { + (Self::ZERO, true) + } else { + let mut rem = self.div_rem_unchecked(rhs).1; + if rem.is_negative() { + if rhs.is_negative() { + rem = rem.wrapping_sub(rhs); } else { - let mut rem = self.div_rem_unchecked(rhs).1; - if rem.is_negative() { - if rhs.is_negative() { - rem = rem.wrapping_sub(rhs); - } else { - rem = rem.wrapping_add(rhs); - } - } - (rem, false) + rem = rem.wrapping_add(rhs); } } + (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); - } + #[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; } - let (s, o) = - (!self.bits.digits[i] as digit::$Digit::SignedDigit).overflowing_add(1); - self.bits.digits[i] = s as $Digit; - (self, o) + return (self, false); } + i += 1; + } + let (s, o) = (!self.bits.digits[i] as digit::SignedDigit).overflowing_add(1); + self.bits.digits[i] = s as Digit; + (self, o) + } - #[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::(bits, shift) - } else { - $BUint::unchecked_shr_pad_internal::(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() { + BUintD8::unchecked_shr_pad_internal::(bits, shift) + } else { + BUintD8::unchecked_shr_pad_internal::(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)] -crate::test::all_digit_tests! { - use crate::test::{test_bignum, types::itest}; +mod tests { + use crate::test::{test_bignum, types::*}; test_bignum! { function: ::overflowing_add(a: itest, b: itest) @@ -343,5 +339,3 @@ crate::test::all_digit_tests! { function: ::overflowing_pow(a: itest, b: u16) } } - -crate::macro_impl!(overflowing); diff --git a/src/bint/radix.rs b/src/bint/radix.rs index 3d5c491..172a465 100644 --- a/src/bint/radix.rs +++ b/src/bint/radix.rs @@ -1,3 +1,6 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + use crate::doc; use crate::errors::ParseIntError; use crate::int::radix::assert_range; @@ -5,171 +8,169 @@ use alloc::string::String; use alloc::vec::Vec; use core::num::IntErrorKind; -macro_rules! radix { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::radix::impl_desc!($BInt)] - impl $BInt { - /// Converts a byte slice in a given base to an integer. The input slice must contain ascii/utf8 characters in [0-9a-zA-Z]. - /// - /// This function is equivalent to the [`from_str_radix`](#method.from_str_radix) function for a string slice equivalent to the byte slice and the same radix. - /// - /// Returns `None` if the conversion of the byte slice to string slice fails or if a digit is larger than or equal to the given radix, otherwise the integer is wrapped in `Some`. - #[inline] - pub const fn parse_bytes(buf: &[u8], radix: u32) -> Option { - let s = crate::nightly::option_try!(crate::nightly::ok!(core::str::from_utf8(buf))); - crate::nightly::ok!(Self::from_str_radix(s, radix)) - } +#[doc = doc::radix::impl_desc!(BIntD8)] +impl BIntD8 { + /// Converts a byte slice in a given base to an integer. The input slice must contain ascii/utf8 characters in [0-9a-zA-Z]. + /// + /// This function is equivalent to the [`from_str_radix`](#method.from_str_radix) function for a string slice equivalent to the byte slice and the same radix. + /// + /// Returns `None` if the conversion of the byte slice to string slice fails or if a digit is larger than or equal to the given radix, otherwise the integer is wrapped in `Some`. + #[inline] + pub const fn parse_bytes(buf: &[u8], radix: u32) -> Option { + let s = crate::nightly::option_try!(crate::nightly::ok!(core::str::from_utf8(buf))); + crate::nightly::ok!(Self::from_str_radix(s, radix)) + } - /// 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_be`](crate::", stringify!(BUintD8), "::from_radix_be) method documentation for [`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ").")] + #[inline] + pub const fn from_radix_be(buf: &[u8], radix: u32) -> Option { + match BUintD8::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!(BUintD8), "::from_radix_le) method documentation for [`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ").")] + #[inline] + pub const fn from_radix_le(buf: &[u8], radix: u32) -> Option { + match BUintD8::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. - /// - /// The string is expected to be an optional `+` or `-` sign followed by digits. Leading and trailing whitespace represent an error. Digits are a subset of these characters, depending on `radix`: - /// - /// - `0-9` - /// - `a-z` - /// - `A-Z` - /// - /// # Panics - /// - /// 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), ").")] - #[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; - } + /// Converts a string slice in a given base to an integer. + /// + /// The string is expected to be an optional `+` or `-` sign followed by digits. Leading and trailing whitespace represent an error. Digits are a subset of these characters, depending on `radix`: + /// + /// - `0-9` + /// - `a-z` + /// - `A-Z` + /// + /// # Panics + /// + /// 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!(BUintD8), "::from_str_radix) method documentation for [`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ").")] + #[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; + } - 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 { - Err(ParseIntError { - kind: IntErrorKind::NegOverflow, - }) - } else { - Ok(Self::from_bits(uint).wrapping_neg()) - } - } else { - let out = Self::from_bits(uint); - if out.is_negative() { - Err(ParseIntError { - kind: IntErrorKind::PosOverflow, - }) - } else { - Ok(out) - } - } + match BUintD8::from_buf_radix_internal::(buf, radix, leading_sign) { + Ok(uint) => { + if negative { + if uint.bit(Self::BITS - 1) && uint.trailing_zeros() != Self::BITS - 1 { + Err(ParseIntError { + kind: IntErrorKind::NegOverflow, + }) + } else { + Ok(Self::from_bits(uint).wrapping_neg()) } - Err(err) => { - if let IntErrorKind::PosOverflow = err.kind() { - if negative { - return Err(ParseIntError { - kind: IntErrorKind::NegOverflow, - }); - } - } - return Err(err) + } else { + let out = Self::from_bits(uint); + if out.is_negative() { + Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }) + } else { + Ok(out) } } } - - #[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. - /// - /// # Panics - /// - /// 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), ").")] - #[inline] - pub fn to_str_radix(&self, radix: u32) -> String { - if self.is_negative() { - format!("-{}", self.unsigned_abs().to_str_radix(radix)) - } else { - self.bits.to_str_radix(radix) + Err(err) => { + if let IntErrorKind::PosOverflow = err.kind() { + if negative { + return Err(ParseIntError { + kind: IntErrorKind::NegOverflow, + }); + } } + return Err(err); } + } + } - /// Returns the integer's underlying representation as an unsigned integer in the given base in big-endian digit order. - /// - /// # Panics - /// - /// 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), "`]")] - #[inline] - pub fn to_radix_be(&self, radix: u32) -> Vec { - self.bits.to_radix_be(radix) - } + #[doc = doc::radix::parse_str_radix!(BUintD8)] + #[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's underlying representation as an unsigned integer in the given base in little-endian digit order. - /// - /// # Panics - /// - /// 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), ").")] - #[inline] - pub fn to_radix_le(&self, radix: u32) -> Vec { - self.bits.to_radix_le(radix) - } + /// Returns the integer as a string in the given radix. + /// + /// # Panics + /// + /// 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!(BUintD8), "::to_str_radix) method documentation for [`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ").")] + #[inline] + pub fn to_str_radix(&self, radix: u32) -> String { + if self.is_negative() { + format!("-{}", self.unsigned_abs().to_str_radix(radix)) + } else { + self.bits.to_str_radix(radix) } - }; + } + + /// Returns the integer's underlying representation as an unsigned integer in the given base in big-endian digit order. + /// + /// # Panics + /// + /// 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!(BUintD8), "::to_radix_be) method documentation for [`", stringify!(BUintD8), "`]")] + #[inline] + pub fn to_radix_be(&self, radix: u32) -> Vec { + self.bits.to_radix_be(radix) + } + + /// Returns the integer's underlying representation as an unsigned integer in the given base in little-endian digit order. + /// + /// # Panics + /// + /// 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!(BUintD8), "::to_radix_le) method documentation for [`", stringify!(BUintD8), "`](crate::", stringify!(BUintD8), ").")] + #[inline] + pub fn to_radix_le(&self, radix: u32) -> Vec { + self.bits.to_radix_le(radix) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::{quickcheck_from_to_radix, test_bignum, self}; - use crate::test::types::itest; - use crate::BInt; + use crate::test::types::*; + use crate::BIntD8; test_bignum! { function: ::from_str_radix, @@ -206,14 +207,14 @@ crate::test::all_digit_tests! { 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 u = BIntD8::<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); + let option = BIntD8::<100>::from_radix_le(buf, 78); assert!(option.is_none()); let buf = &[ @@ -221,7 +222,7 @@ crate::test::all_digit_tests! { 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 u = BIntD8::<100>::from_radix_le(buf, 5).unwrap(); let v = u.to_radix_le(5); assert_eq!(v, buf); } @@ -231,7 +232,7 @@ crate::test::all_digit_tests! { 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 u = BIntD8::<100>::from_radix_be(buf, 157).unwrap(); let v = u.to_radix_be(157); assert_eq!(v, buf); @@ -241,7 +242,7 @@ crate::test::all_digit_tests! { 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 u = BIntD8::<100>::from_radix_be(buf, 2).unwrap(); let v = u.to_radix_be(2); assert_eq!(v, buf); @@ -249,48 +250,46 @@ crate::test::all_digit_tests! { 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); + let option = BIntD8::<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 u = BIntD8::<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 u = BIntD8::<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); + let result = BIntD8::<1>::from_str_radix(src, 36); assert!(result.is_err()); let invalid = "inval_id string"; - let result = BInt::<1>::from_str_radix(invalid, 36); + let result = BIntD8::<1>::from_str_radix(invalid, 36); assert!(result.is_err()); let src = "72954hslfhbui79845y6audfgiu984h5ihhhdfg"; - let u = BInt::<100>::from_str_radix(src, 36).unwrap(); + let u = BIntD8::<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(); + let u = BIntD8::<100>::parse_bytes(src.as_bytes(), 16).unwrap(); + let v = BIntD8::<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); + let option = BIntD8::<100>::parse_bytes(bytes, 11); assert!(option.is_none()); } } - -crate::macro_impl!(radix); diff --git a/src/bint/saturating.rs b/src/bint/saturating.rs index 541cff3..7a579cc 100644 --- a/src/bint/saturating.rs +++ b/src/bint/saturating.rs @@ -1,130 +1,129 @@ -use crate::{doc, ExpType}; +use super::BIntD8; +use crate::{BUintD8, Digit}; -macro_rules! saturating { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::saturating::impl_desc!()] - impl $BInt { - #[doc = doc::saturating::saturating_add!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - match self.checked_add(rhs) { - Some(add) => add, - None => { - if self.is_negative() { - Self::MIN - } else { - Self::MAX - } - } - } - } +use crate::{doc, ExpType}; - #[doc = doc::saturating::saturating_add_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_add_unsigned(self, rhs: $BUint) -> Self { - match self.checked_add_unsigned(rhs) { - Some(i) => i, - None => Self::MAX, +#[doc = doc::saturating::impl_desc!()] +impl BIntD8 { + #[doc = doc::saturating::saturating_add!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + match self.checked_add(rhs) { + Some(add) => add, + None => { + if self.is_negative() { + Self::MIN + } else { + Self::MAX } } + } + } - #[doc = doc::saturating::saturating_sub!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - match self.checked_sub(rhs) { - Some(add) => add, - None => { - if self.is_negative() { - Self::MIN - } else { - Self::MAX - } - } - } - } + #[doc = doc::saturating::saturating_add_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_add_unsigned(self, rhs: BUintD8) -> Self { + match self.checked_add_unsigned(rhs) { + Some(i) => i, + None => Self::MAX, + } + } - #[doc = doc::saturating::saturating_sub_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_sub_unsigned(self, rhs: $BUint) -> Self { - match self.checked_sub_unsigned(rhs) { - Some(i) => i, - None => Self::MIN, + #[doc = doc::saturating::saturating_sub!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + match self.checked_sub(rhs) { + Some(add) => add, + None => { + if self.is_negative() { + Self::MIN + } else { + Self::MAX } } + } + } - #[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 - } - } - } - } + #[doc = doc::saturating::saturating_sub_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_sub_unsigned(self, rhs: BUintD8) -> Self { + match self.checked_sub_unsigned(rhs) { + Some(i) => i, + None => Self::MIN, + } + } - #[doc = doc::saturating::saturating_div!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_div(self, rhs: Self) -> Self { - let (div, overflow) = self.overflowing_div(rhs); - if overflow { + #[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 { - div + Self::MIN } } + } + } - #[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_div!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_div(self, rhs: Self) -> Self { + let (div, overflow) = self.overflowing_div(rhs); + if overflow { + Self::MAX + } else { + div + } + } - #[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_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_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)] -crate::test::all_digit_tests! { +mod tests { use crate::test::{test_bignum, types::*}; test_bignum! { @@ -165,5 +164,3 @@ crate::test::all_digit_tests! { function: ::saturating_pow(a: itest, b: u16) } } - -crate::macro_impl!(saturating); diff --git a/src/bint/strict.rs b/src/bint/strict.rs index 067e973..9207551 100644 --- a/src/bint/strict.rs +++ b/src/bint/strict.rs @@ -1,46 +1,46 @@ -macro_rules! strict { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::strict::impl_desc!()] - impl $BInt { - crate::int::strict::impls!(I); - - #[doc = doc::strict::strict_abs!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn strict_abs(self) -> Self { - crate::errors::option_expect!( - self.checked_abs(), - crate::errors::err_msg!("attempt to negate with overflow") - ) - } - - #[doc = doc::strict::strict_add_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn strict_add_unsigned(self, rhs: $BUint) -> Self { - crate::errors::option_expect!( - self.checked_add_unsigned(rhs), - crate::errors::err_msg!("attempt to add with overflow") - ) - } - - #[doc = doc::strict::strict_sub_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn strict_sub_unsigned(self, rhs: $BUint) -> Self { - crate::errors::option_expect!( - self.checked_sub_unsigned(rhs), - crate::errors::err_msg!("attempt to subtract with overflow") - ) - } - } - }; +use super::BIntD8; +use crate::{BUintD8, Digit}; + + +#[doc = doc::strict::impl_desc!()] +impl BIntD8 { + crate::int::strict::impls!(I); + + #[doc = doc::strict::strict_abs!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn strict_abs(self) -> Self { + crate::errors::option_expect!( + self.checked_abs(), + crate::errors::err_msg!("attempt to negate with overflow") + ) + } + + #[doc = doc::strict::strict_add_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn strict_add_unsigned(self, rhs: BUintD8) -> Self { + crate::errors::option_expect!( + self.checked_add_unsigned(rhs), + crate::errors::err_msg!("attempt to add with overflow") + ) + } + + #[doc = doc::strict::strict_sub_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn strict_sub_unsigned(self, rhs: BUintD8) -> Self { + crate::errors::option_expect!( + self.checked_sub_unsigned(rhs), + crate::errors::err_msg!("attempt to subtract with overflow") + ) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { crate::int::strict::tests!(itest); - + test_bignum! { function: ::strict_abs(a: itest), skip: a.checked_abs().is_none() @@ -56,5 +56,3 @@ crate::test::all_digit_tests! { } use crate::doc; - -crate::macro_impl!(strict); diff --git a/src/bint/unchecked.rs b/src/bint/unchecked.rs index c5f5fea..c438038 100644 --- a/src/bint/unchecked.rs +++ b/src/bint/unchecked.rs @@ -1,14 +1,12 @@ -macro_rules! unchecked { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - crate::int::unchecked::impls!($BInt, I); - }; -} +use super::BIntD8; +use crate::{BUintD8, Digit}; + + +crate::int::unchecked::impls!(BIntD8, I); #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { crate::int::unchecked::tests!(itest); } use crate::doc; - -crate::macro_impl!(unchecked); diff --git a/src/bint/wrapping.rs b/src/bint/wrapping.rs index 85e8ead..aa62f66 100644 --- a/src/bint/wrapping.rs +++ b/src/bint/wrapping.rs @@ -1,114 +1,113 @@ +use super::BIntD8; +use crate::{BUintD8, Digit}; + use crate::{doc, ExpType}; -macro_rules! wrapping { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::wrapping::impl_desc!()] - impl $BInt { - #[doc = doc::wrapping::wrapping_add!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { - Self::from_bits(self.bits.wrapping_add(rhs.bits)) - } - - #[doc = doc::wrapping::wrapping_add_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_add_unsigned(self, rhs: $BUint) -> Self { - self.overflowing_add_unsigned(rhs).0 - } - - #[doc = doc::wrapping::wrapping_sub!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - Self::from_bits(self.bits.wrapping_sub(rhs.bits)) - } - - #[doc = doc::wrapping::wrapping_sub_unsigned!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_sub_unsigned(self, rhs: $BUint) -> Self { - self.overflowing_sub_unsigned(rhs).0 - } - - #[doc = doc::wrapping::wrapping_mul!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - Self::from_bits(self.bits.wrapping_mul(rhs.bits)) - } - - #[doc = doc::wrapping::wrapping_div!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - self.overflowing_div(rhs).0 - } - - #[doc = doc::wrapping::wrapping_div_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self.overflowing_div_euclid(rhs).0 - } - - #[doc = doc::wrapping::wrapping_rem!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - self.overflowing_rem(rhs).0 - } - - #[doc = doc::wrapping::wrapping_rem_euclid!(I)] - #[must_use = doc::must_use_op!()] - #[inline] - 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_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_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!()] - #[inline] - pub const fn wrapping_pow(self, pow: ExpType) -> Self { - // as wrapping_mul for signed and unsigned is the same - Self::from_bits(self.bits.wrapping_pow(pow)) - } - } - }; +#[doc = doc::wrapping::impl_desc!()] +impl BIntD8 { + #[doc = doc::wrapping::wrapping_add!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_add(self, rhs: Self) -> Self { + Self::from_bits(self.bits.wrapping_add(rhs.bits)) + } + + #[doc = doc::wrapping::wrapping_add_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_add_unsigned(self, rhs: BUintD8) -> Self { + self.overflowing_add_unsigned(rhs).0 + } + + #[doc = doc::wrapping::wrapping_sub!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + Self::from_bits(self.bits.wrapping_sub(rhs.bits)) + } + + #[doc = doc::wrapping::wrapping_sub_unsigned!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_sub_unsigned(self, rhs: BUintD8) -> Self { + self.overflowing_sub_unsigned(rhs).0 + } + + #[doc = doc::wrapping::wrapping_mul!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + Self::from_bits(self.bits.wrapping_mul(rhs.bits)) + } + + #[doc = doc::wrapping::wrapping_div!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + self.overflowing_div(rhs).0 + } + + #[doc = doc::wrapping::wrapping_div_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self.overflowing_div_euclid(rhs).0 + } + + #[doc = doc::wrapping::wrapping_rem!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + self.overflowing_rem(rhs).0 + } + + #[doc = doc::wrapping::wrapping_rem_euclid!(I)] + #[must_use = doc::must_use_op!()] + #[inline] + 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_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_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!()] + #[inline] + pub const fn wrapping_pow(self, pow: ExpType) -> Self { + // as wrapping_mul for signed and unsigned is the same + Self::from_bits(self.bits.wrapping_pow(pow)) + } } #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::{test_bignum, types::{itest, utest}}; +mod tests { + use crate::test::{test_bignum, types::*}; test_bignum! { function: ::wrapping_add(a: itest, b: itest) @@ -164,5 +163,3 @@ crate::test::all_digit_tests! { function: ::wrapping_pow(a: itest, b: u16) } } - -crate::macro_impl!(wrapping); diff --git a/src/buint/bigint_helpers.rs b/src/buint/bigint_helpers.rs index 507a873..2df3484 100644 --- a/src/buint/bigint_helpers.rs +++ b/src/buint/bigint_helpers.rs @@ -1,67 +1,64 @@ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit}; use crate::doc; -macro_rules! bigint_helpers { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::bigint_helpers::impl_desc!()] - impl $BUint { - crate::int::bigint_helpers::impls!(U); +#[doc = doc::bigint_helpers::impl_desc!()] +impl BUintD8 { + crate::int::bigint_helpers::impls!(U); - #[doc = doc::bigint_helpers::widening_mul!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { - let mut low = Self::ZERO; - let mut high = Self::ZERO; - let mut carry: $Digit; + #[doc = doc::bigint_helpers::widening_mul!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn widening_mul(self, rhs: Self) -> (Self, Self) { + let mut low = Self::ZERO; + let mut high = Self::ZERO; + let mut carry: Digit; - let mut i = 0; - while i < N { - carry = 0; - let mut j = 0; - while j < N - i { - let index = i + j; - let d = low.digits[index]; - let (new_digit, new_carry) = - digit::$Digit::carrying_mul(self.digits[i], rhs.digits[j], carry, d); - carry = new_carry; - low.digits[index] = new_digit; - j += 1; - } - while j < N { - let index = i + j - N; - let d = high.digits[index]; - let (new_digit, new_carry) = - digit::$Digit::carrying_mul(self.digits[i], rhs.digits[j], carry, d); - carry = new_carry; - high.digits[index] = new_digit; - j += 1; - } - high.digits[i] = carry; - i += 1; - } - - (low, high) + let mut i = 0; + while i < N { + carry = 0; + let mut j = 0; + while j < N - i { + let index = i + j; + let d = low.digits[index]; + let (new_digit, new_carry) = + digit::carrying_mul(self.digits[i], rhs.digits[j], carry, d); + carry = new_carry; + low.digits[index] = new_digit; + j += 1; } - - #[doc = doc::bigint_helpers::carrying_mul!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { - let (low, high) = self.widening_mul(rhs); - let (low, overflow) = low.overflowing_add(carry); - if overflow { - (low, high.wrapping_add(Self::ONE)) - } else { - (low, high) - } + while j < N { + let index = i + j - N; + let d = high.digits[index]; + let (new_digit, new_carry) = + digit::carrying_mul(self.digits[i], rhs.digits[j], carry, d); + carry = new_carry; + high.digits[index] = new_digit; + j += 1; } + high.digits[i] = carry; + i += 1; + } + + (low, high) + } + + #[doc = doc::bigint_helpers::carrying_mul!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) { + let (low, high) = self.widening_mul(rhs); + let (low, overflow) = low.overflowing_add(carry); + if overflow { + (low, high.wrapping_add(Self::ONE)) + } else { + (low, high) } - }; + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { crate::int::bigint_helpers::tests!(utest); #[cfg(test_int_bits = "64")] @@ -81,5 +78,3 @@ crate::test::all_digit_tests! { ] } } - -crate::macro_impl!(bigint_helpers); diff --git a/src/buint/cast.rs b/src/buint/cast.rs index a78a349..62dfabd 100644 --- a/src/buint/cast.rs +++ b/src/buint/cast.rs @@ -1,3 +1,6 @@ +use super::BUintD8; +use crate::{digit, Digit}; + macro_rules! decode_float { ($name: ident, $f: ty, $u: ty) => { pub fn $name(f: $f) -> ($u, i16) { @@ -21,16 +24,16 @@ decode_float!(decode_f32, f32, u32); decode_float!(decode_f64, f64, u64); macro_rules! buint_as_int { - ($BUint: ident, $Digit: ident; $($int: ty), *) => { + ($($int: ty), *) => { $( - impl CastFrom<$BUint> for $int { + impl CastFrom> for $int { #[must_use = doc::must_use_op!()] #[inline] - fn cast_from(from: $BUint) -> Self { + fn cast_from(from: BUintD8) -> 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); + while i << crate::digit::BIT_SHIFT < <$int>::BITS as usize && i < N { + out |= from.digits[i] as $int << (i << crate::digit::BIT_SHIFT); i += 1; } out @@ -41,11 +44,11 @@ macro_rules! buint_as_int { } macro_rules! buint_as_float { - ($BUint: ident, $f: ty) => { - impl CastFrom<$BUint> for $f { + ($f: ty) => { + impl CastFrom> for $f { #[must_use = doc::must_use_op!()] #[inline] - fn cast_from(value: $BUint) -> Self { + fn cast_from(value: BUintD8) -> Self { crate::cast::float::cast_float_from_uint(value) } } @@ -53,9 +56,9 @@ macro_rules! buint_as_float { } macro_rules! as_buint { - ($BUint: ident, $Digit: ident; $($ty: ty), *) => { + ($($ty: ty), *) => { $( - impl CastFrom<$ty> for $BUint { + impl CastFrom<$ty> for BUintD8 { #[must_use = doc::must_use_op!()] #[inline] fn cast_from(mut from: $ty) -> Self { @@ -67,12 +70,12 @@ macro_rules! as_buint { }; let mut i = 0; while from != 0 && i < N { - let masked = from as $Digit & $Digit::MAX; + let masked = from as Digit & Digit::MAX; out.digits[i] = masked; - if <$ty>::BITS <= $Digit::BITS { + if <$ty>::BITS <= Digit::BITS { from = 0; } else { - from = from.wrapping_shr($Digit::BITS); + from = from.wrapping_shr(Digit::BITS); } i += 1; } @@ -83,165 +86,157 @@ macro_rules! as_buint { }; } +#[allow(unused_imports)] +use crate::cast::float::{CastFloatFromUintHelper, CastUintFromFloatHelper, FloatMantissa}; use crate::cast::CastFrom; use crate::doc; use crate::ExpType; -#[allow(unused_imports)] -use crate::cast::float::{FloatMantissa, CastUintFromFloatHelper, CastFloatFromUintHelper}; -macro_rules! cast { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - // #[cfg(feature = "float")] - // impl FloatMantissa for $BUint { - // const ZERO: Self = Self::ZERO; - // const ONE: Self = Self::ONE; - // const TWO: Self = Self::TWO; - // const MAX: Self = Self::MAX; +// #[cfg(feature = "float")] +// impl FloatMantissa for BUintD8 { +// const ZERO: Self = Self::ZERO; +// const ONE: Self = Self::ONE; +// const TWO: Self = Self::TWO; +// const MAX: Self = Self::MAX; - // #[inline] - // fn leading_zeros(self) -> ExpType { - // Self::leading_zeros(self) - // } +// #[inline] +// fn leading_zeros(self) -> ExpType { +// Self::leading_zeros(self) +// } - // #[inline] - // fn checked_shr(self, n: ExpType) -> Option { - // Self::checked_shr(self, n) - // } +// #[inline] +// fn checked_shr(self, n: ExpType) -> Option { +// Self::checked_shr(self, n) +// } - // #[inline] - // fn is_power_of_two(self) -> bool { - // Self::is_power_of_two(self) - // } - // } +// #[inline] +// fn is_power_of_two(self) -> bool { +// Self::is_power_of_two(self) +// } +// } - impl CastUintFromFloatHelper for $BUint { - const MAX: Self = Self::MAX; - const MIN: Self = Self::MIN; - } +impl CastUintFromFloatHelper for BUintD8 { + const MAX: Self = Self::MAX; + const MIN: Self = Self::MIN; +} - impl CastFloatFromUintHelper for $BUint { - fn trailing_zeros(self) -> ExpType { - Self::trailing_zeros(self) - } - } +impl CastFloatFromUintHelper for BUintD8 { + fn trailing_zeros(self) -> ExpType { + Self::trailing_zeros(self) + } +} - impl $BUint { - #[inline] - const fn cast_up(self, digit: $Digit) -> $BUint { - let mut digits = [digit; M]; - let mut i = M - N; - while i < M { - let index = i - (M - N); - digits[index] = self.digits[index]; - i += 1; - } - $BUint::from_digits(digits) - } +impl BUintD8 { + #[inline] + const fn cast_up(self, digit: Digit) -> BUintD8 { + let mut digits = [digit; M]; + let mut i = M - N; + while i < M { + let index = i - (M - N); + digits[index] = self.digits[index]; + i += 1; + } + BUintD8::from_digits(digits) + } - #[inline] - const fn cast_down(self) -> $BUint { - let mut out = $BUint::ZERO; - let mut i = 0; - while i < M { - out.digits[i] = self.digits[i]; - i += 1; - } - out - } + #[inline] + const fn cast_down(self) -> BUintD8 { + let mut out = BUintD8::ZERO; + let mut i = 0; + while i < M { + out.digits[i] = self.digits[i]; + i += 1; } + out + } +} - buint_as_int!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); +buint_as_int!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - buint_as_float!($BUint, f32); - buint_as_float!($BUint, f64); +buint_as_float!(f32); +buint_as_float!(f64); - as_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); +as_buint!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - impl CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: bool) -> Self { - if from { - Self::ONE - } else { - Self::ZERO - } - } +impl CastFrom for BUintD8 { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: bool) -> Self { + if from { + Self::ONE + } else { + Self::ZERO } + } +} - impl CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: char) -> Self { - Self::cast_from(from as u32) - } - } +impl CastFrom for BUintD8 { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: char) -> Self { + Self::cast_from(from as u32) + } +} - impl 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 CastFrom> for BUintD8 { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: BUintD8) -> Self { + if M < N { + from.cast_up(0) + } else { + from.cast_down() } + } +} - impl 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 CastFrom> for BUintD8 { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: crate::BIntD8) -> 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 CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(value: f32) -> Self { - crate::cast::float::cast_uint_from_float(value) - } - } +impl CastFrom for BUintD8 { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(value: f32) -> Self { + crate::cast::float::cast_uint_from_float(value) + } +} - impl CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(value: f64) -> Self { - crate::cast::float::cast_uint_from_float(value) - } - } - }; +impl CastFrom for BUintD8 { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(value: f64) -> Self { + crate::cast::float::cast_uint_from_float(value) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { + use crate::test::types::*; + crate::int::cast::tests!(utest); } -crate::macro_impl!(cast); - macro_rules! buint_as_different_digit_bigint { - ($BUint: ident, $BInt: ident, $Digit: ident; $(($OtherBUint: ident, $OtherDigit: ident)), *) => { + (BUintD8: ident, BIntD8: ident, Digit: ident; $(($OtherBUint: ident, $OtherDigit: ident)), *) => { $( - impl crate::cast::CastFrom<$OtherBUint> for $BUint { + impl crate::cast::CastFrom<$OtherBUint> for BUintD8 { #[must_use = doc::must_use_op!()] #[inline] fn cast_from(from: $OtherBUint) -> Self { let mut out = Self::ZERO; - if $Digit::BITS < $OtherDigit::BITS { - const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize; - let stop_index: usize = if <$OtherBUint>::BITS > <$BUint>::BITS { + if Digit::BITS < $OtherDigit::BITS { + const DIVIDE_COUNT: usize = ($OtherDigit::BITS / Digit::BITS) as usize; + let stop_index: usize = if <$OtherBUint>::BITS > >::BITS { N } else { M * DIVIDE_COUNT @@ -250,22 +245,22 @@ macro_rules! buint_as_different_digit_bigint { while i < stop_index { let wider_digit = from.digits[i / DIVIDE_COUNT]; let mini_shift = i % DIVIDE_COUNT; - let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit; + let digit = (wider_digit >> (mini_shift << digit::BIT_SHIFT)) as Digit; out.digits[i] = digit; i += 1; } } else { - const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize; - let stop_index: usize = if <$OtherBUint>::BITS > <$BUint>::BITS { + const DIVIDE_COUNT: usize = (Digit::BITS / $OtherDigit::BITS) as usize; + let stop_index: usize = if <$OtherBUint>::BITS > >::BITS { N * DIVIDE_COUNT } else { M }; - let mut current_digit: $Digit = 0; + let mut current_digit: Digit = 0; let mut i = 0; while i < stop_index { let mini_shift = i % DIVIDE_COUNT; - current_digit |= (from.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT); + current_digit |= (from.digits[i] as Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT); if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 { out.digits[i / DIVIDE_COUNT] = current_digit; current_digit = 0; @@ -277,15 +272,15 @@ macro_rules! buint_as_different_digit_bigint { } } - impl crate::cast::CastFrom<$OtherBUint> for $BInt { + impl crate::cast::CastFrom<$OtherBUint> for BIntD8 { #[must_use = doc::must_use_op!()] #[inline] fn cast_from(from: $OtherBUint) -> Self { - Self::from_bits($BUint::cast_from(from)) + Self::from_bits(BUintD8::cast_from(from)) } } )* } } -pub(crate) use buint_as_different_digit_bigint; \ No newline at end of file +pub(crate) use buint_as_different_digit_bigint; diff --git a/src/buint/checked.rs b/src/buint/checked.rs index 3ba7a7a..6bf6ff6 100644 --- a/src/buint/checked.rs +++ b/src/buint/checked.rs @@ -1,277 +1,269 @@ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit, BIntD8}; use crate::doc; use crate::errors::div_zero; use crate::helpers::tuple_to_option; 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::impl_desc!()] +impl BUintD8 { + #[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_add_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn checked_add_signed(self, rhs: BIntD8) -> 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_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)) - } + #[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)) + } - 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) - } - - - #[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 - } - } + 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::div_rem_wide(self.digits[i], rem, rhs); + rem = r; + out.digits[i] = q; + } + (out, rem) + } - #[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)) - } - } - } + #[inline] + pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) { + use core::cmp::Ordering; - #[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 + 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 { - unsafe { - Some(Self::unchecked_shr_internal(self, rhs)) - } + self.basecase_div_rem(rhs, ldi + 1) } } + } + } - #[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) - } + #[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_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_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_ilog2!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_ilog2(self) -> Option { - self.bits().checked_sub(1) + #[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) + } - #[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) + #[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 { - 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)) - } + // `next_multiple = floor(self / rhs) * rhs + rhs = (self - rem) + rhs` + self.checked_add(rhs.sub(rem)) } } + None => None, + } + } + + #[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) + } + + #[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_ilog10!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn checked_ilog10(self) -> Option { + #[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 Self::TEN.gt(&self) { + if base.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) - } - } + Some(Self::iilog(1, base, self.div(base)).0) } + } + } - #[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)) - } + #[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)] -crate::test::all_digit_tests! { +mod tests { use crate::test::{test_bignum, types::*}; test_bignum! { @@ -337,5 +329,3 @@ crate::test::all_digit_tests! { ] } } - -crate::macro_impl!(checked); diff --git a/src/buint/cmp.rs b/src/buint/cmp.rs index 1221bde..2f0fdc4 100644 --- a/src/buint/cmp.rs +++ b/src/buint/cmp.rs @@ -1,41 +1,37 @@ +use super::BUintD8; +use crate::{digit, Digit}; use core::cmp::{Ord, Ordering, PartialOrd}; -macro_rules! cmp { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl PartialOrd for $BUint { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } +impl PartialOrd for BUintD8 { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} - impl Ord for $BUint { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - Self::cmp(self, other) - } +impl Ord for BUintD8 { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Self::cmp(self, other) + } - #[inline] - fn max(self, other: Self) -> Self { - Self::max(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 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 clamp(self, min: Self, max: Self) -> Self { + Self::clamp(self, min, max) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { crate::int::cmp::tests!(utest); } - -crate::macro_impl!(cmp); diff --git a/src/buint/const_trait_fillers.rs b/src/buint/const_trait_fillers.rs index ce34646..d895633 100644 --- a/src/buint/const_trait_fillers.rs +++ b/src/buint/const_trait_fillers.rs @@ -1,106 +1,102 @@ +use super::BUintD8; +use crate::{digit, Digit}; 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 - } +#[doc = doc::const_trait_fillers::impl_desc!()] +impl BUintD8 { + #[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!(); - #[inline] - pub const fn div(self, rhs: Self) -> Self { - self.wrapping_div(rhs) - } + #[inline] + pub const fn div(self, rhs: Self) -> Self { + self.wrapping_div(rhs) + } - #[inline] - pub const fn rem(self, rhs: Self) -> Self { - self.wrapping_rem(rhs) - } - } - }; + #[inline] + pub const fn rem(self, rhs: Self) -> Self { + self.wrapping_rem(rhs) + } } - -crate::macro_impl!(const_trait_fillers); diff --git a/src/buint/consts.rs b/src/buint/consts.rs index 8fda9e2..31138ab 100644 --- a/src/buint/consts.rs +++ b/src/buint/consts.rs @@ -1,3 +1,6 @@ +use super::BUintD8; +use crate::{digit, Digit}; + macro_rules! pos_const { ($($name: ident $num: literal), *) => { $( @@ -7,32 +10,25 @@ macro_rules! pos_const { } } -use crate::digit; 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]); +#[doc = doc::consts::impl_desc!()] +impl BUintD8 { + #[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::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 1f4ad60..eb06102 100644 --- a/src/buint/convert.rs +++ b/src/buint/convert.rs @@ -1,14 +1,17 @@ +use super::BUintD8; +use crate::{digit, Digit}; + macro_rules! from_uint { - ($BUint: ident, $Digit: ident; $($uint: tt),*) => { + ($($uint: tt),*) => { $( - impl From<$uint> for $BUint { + impl From<$uint> for BUintD8 { #[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; + while i << crate::digit::BIT_SHIFT < UINT_BITS { + let d = (int >> (i << crate::digit::BIT_SHIFT)) as Digit; if d != 0 { out.digits[i] = d; } @@ -22,9 +25,9 @@ macro_rules! from_uint { } macro_rules! try_from_iint { - ($BUint: ident; $($int: tt -> $uint: tt),*) => { + ($($int: tt -> $uint: tt),*) => { $( - impl TryFrom<$int> for $BUint { + impl TryFrom<$int> for BUintD8 { type Error = TryFromIntError; #[inline] @@ -41,18 +44,18 @@ macro_rules! try_from_iint { } macro_rules! try_from_buint { - ($BUint: ident, $Digit: ident; $($int: ty), *) => { + ($($int: ty), *) => { $( - impl TryFrom<$BUint> for $int { + impl TryFrom> for $int { type Error = TryFromIntError; #[inline] - fn try_from(u: $BUint) -> Result<$int, Self::Error> { + fn try_from(u: BUintD8) -> Result<$int, Self::Error> { let mut out = 0; let mut i = 0; - if $Digit::BITS > <$int>::BITS { + if Digit::BITS > <$int>::BITS { let small = u.digits[i] as $int; - let trunc = small as $Digit; + let trunc = small as Digit; if u.digits[i] != trunc { return Err(TryFromIntError(())); } @@ -60,7 +63,7 @@ macro_rules! try_from_buint { i = 1; } else { loop { - let shift = i << crate::digit::$Digit::BIT_SHIFT; + let shift = i << crate::digit::BIT_SHIFT; if i >= N || shift >= <$int>::BITS as usize { break; } @@ -80,7 +83,7 @@ macro_rules! try_from_buint { } i += 1; } - + Ok(out) } } @@ -93,7 +96,7 @@ macro_rules! uint_try_from_uint { $( impl<$(const $N: usize,)? const M: usize> $Trait<$From $(<$N>)?> for $To { type Error = TryFromIntError; - + fn try_from(from: $From $(<$N>)?) -> Result { if $From $(::<$N>)?::BITS <= Self::BITS || $From $(::<$N>)?::BITS - from.leading_zeros() <= Self::BITS { Ok(Self::cast_from(from)) @@ -111,7 +114,7 @@ macro_rules! uint_try_from_int { $( impl<$(const $N: usize,)? const M: usize> $Trait<$From $(<$N>)?> for $To { type Error = TryFromIntError; - + fn try_from(from: $From $(<$N>)?) -> Result { if from.is_negative() { Err(TryFromIntError(())) @@ -133,7 +136,7 @@ macro_rules! int_try_from_uint { $( impl<$(const $N: usize,)? const M: usize> $Trait<$From $(<$N>)?> for $To { type Error = TryFromIntError; - + fn try_from(from: $From $(<$N>)?) -> Result { if $From $(::<$N>)?::BITS <= Self::BITS - 1 || $From $(::<$N>)?::BITS - from.leading_zeros() <= Self::BITS - 1 { // Self::BITS - 1 as otherwise return value would be negative Ok(Self::cast_from(from)) @@ -151,7 +154,7 @@ macro_rules! int_try_from_int { $( impl<$(const $N: usize,)? const M: usize> $Trait<$From $(<$N>)?> for $To { type Error = TryFromIntError; - + fn try_from(from: $From $(<$N>)?) -> Result { if $From $(::<$N>)?::BITS <= Self::BITS { return Ok(Self::cast_from(from)); @@ -175,65 +178,48 @@ macro_rules! int_try_from_int { }; } -use crate::BTryFrom; - -macro_rules! mixed_try_from { - ($BUint: ident, $BInt: ident) => { - uint_try_from_uint!(BTryFrom; $BUint; BUint, BUintD32, BUintD16, BUintD8/*, u8, u16, u32, u64, u128, usize*/); - uint_try_from_int!(BTryFrom; $BUint; BInt, BIntD32, BIntD16, BIntD8/*, i8, i16, i32, i64, i128, isize*/); - int_try_from_uint!(BTryFrom; $BInt; BUint, BUintD32, BUintD16, BUintD8/*, u8, u16, u32, u64, u128, usize*/); - int_try_from_int!(BTryFrom; $BInt; BInt, BIntD32, BIntD16, BIntD8/*, i8, i16, i32, i64, i128, isize*/); - }; -} - use crate::cast::CastFrom; use crate::errors::TryFromIntError; -macro_rules! convert { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl From for $BUint { - #[inline] - fn from(small: bool) -> Self { - Self::cast_from(small) - } - } - - impl From for $BUint { - #[inline] - fn from(c: char) -> Self { - Self::cast_from(c) - } - } +impl From for BUintD8 { + #[inline] + fn from(small: bool) -> Self { + Self::cast_from(small) + } +} - from_uint!($BUint, $Digit; u8, u16, u32, u64, u128, usize); +impl From for BUintD8 { + #[inline] + fn from(c: char) -> Self { + Self::cast_from(c) + } +} - try_from_iint!($BUint; i8 -> u8, i16 -> u16, i32 -> u32, isize -> usize, i64 -> u64, i128 -> u128); +from_uint!(u8, u16, u32, u64, u128, usize); - try_from_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); +try_from_iint!(i8 -> u8, i16 -> u16, i32 -> u32, isize -> usize, i64 -> u64, i128 -> u128); - mixed_try_from!($BUint, $BInt); +try_from_buint!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - impl From<[$Digit; N]> for $BUint { - #[inline] - fn from(digits: [$Digit; N]) -> Self { - Self::from_digits(digits) - } - } +impl From<[Digit; N]> for BUintD8 { + #[inline] + fn from(digits: [Digit; N]) -> Self { + Self::from_digits(digits) + } +} - impl From<$BUint> for [$Digit; N] { - #[inline] - fn from(uint: $BUint) -> Self { - uint.digits - } - } - }; +impl From> for [Digit; N] { + #[inline] + fn from(uint: BUintD8) -> Self { + uint.digits + } } #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::{self, types::utest}; +mod tests { + use crate::test::{self, types::*}; use crate::test::cast_types::*; - use super::BTryFrom; + use crate::BTryFrom; test::test_btryfrom!(utest; TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10/*, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize*/); @@ -248,5 +234,3 @@ crate::test::all_digit_tests! { into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize) } } - -crate::macro_impl!(convert); diff --git a/src/buint/div.rs b/src/buint/div.rs index b988ef2..1fa8f09 100644 --- a/src/buint/div.rs +++ b/src/buint/div.rs @@ -1,205 +1,206 @@ +use super::BUintD8; +use crate::{digit, Digit}; use crate::ExpType; -use crate::digit; -macro_rules! div_impl { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl $BUint { - pub(crate) 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 BUintD8 { + pub(crate) 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] } - 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) -> BUintD8 { + let mut out = BUintD8::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::BITS as ExpType - shift); + i += 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 + } + out + } + const fn new(uint: BUintD8, shift: ExpType) -> Self { + let first = uint.digits[0] << shift; + let rest = uint.wrapping_shr(digit::BITS - shift); + Self { + first, + rest: rest.digits, + } + } + /*crate::nightly::const_fns! { + const fn set_digit(&mut self, index: usize, digit: Digit) -> () { + if index == 0 { + self.first = digit; + } else { + self.rest[index - 1] = digit; } - 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 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::borrowing_sub(self.digit(i + start), rhs.digit(i), borrow); + self.set_digit(i + start, sub); + borrow = overflow; + i += 1; } - /*crate::nightly::const_fns! { - 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) - } - } - }*/ - const fn sub(mut self, rhs: Mul, start: usize, range: usize) -> (Self, 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); - if start == 0 && i == 0 { - self.first = sub; - } else { - self.rest[i + start - 1] = sub; - } - borrow = overflow; - i += 1; - } - (self, borrow) + borrow + } + const fn add(&mut self, rhs: BUintD8, start: usize, range: usize) -> () { + let mut carry = false; + let mut i = 0; + while i < range { + let (sum, overflow) = digit::carrying_add(self.digit(i + start), rhs.digits[i], carry); + self.set_digit(i + start, sum); + carry = overflow; + i += 1; } - const fn add(mut self, rhs: $BUint, start: usize, range: usize) -> Self { - 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); - if start == 0 && i == 0 { - self.first = sum; - } else { - self.rest[i + start - 1] = sum; - } - carry = overflow; - i += 1; - } - if carry { - if start == 0 && range == 0 { - self.first = self.first.wrapping_add(1); - } else { - self.rest[range + start - 1] = self.rest[range + start - 1].wrapping_add(1); - } - } - self + 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 sub(mut self, rhs: Mul, start: usize, range: usize) -> (Self, bool) { + let mut borrow = false; + let mut i = 0; + while i <= range { + let (sub, overflow) = + digit::borrowing_sub(self.digit(i + start), rhs.digit(i), borrow); + if start == 0 && i == 0 { + self.first = sub; + } else { + self.rest[i + start - 1] = sub; } - const fn digit(&self, index: usize) -> $Digit { - if index == M { - self.last - } else { - self.rest[index] - } + borrow = overflow; + i += 1; + } + (self, borrow) + } + const fn add(mut self, rhs: BUintD8, start: usize, range: usize) -> Self { + let mut carry = false; + let mut i = 0; + while i < range { + let (sum, overflow) = + digit::carrying_add(self.digit(i + start), rhs.digits[i], carry); + if start == 0 && i == 0 { + self.first = sum; + } else { + self.rest[i + start - 1] = sum; } + carry = overflow; + i += 1; } - - 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 + if carry { + if start == 0 && range == 0 { + self.first = self.first.wrapping_add(1); + } else { + self.rest[range + start - 1] = self.rest[range + start - 1].wrapping_add(1); } - - // 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)) { + } + self + } + } + + #[derive(Clone, Copy)] + struct Mul { + last: Digit, + rest: [Digit; M], + } + impl Mul { + const fn new(uint: BUintD8, rhs: Digit) -> Self { + let mut rest = [0; M]; + let mut carry: Digit = 0; + let mut i = 0; + while i < M { + let (prod, c) = 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::div_rem_wide(u.digit(j + n - 1), u_jn, v_n_m1); // D3 + + if tuple_gt( + 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::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 (u_new, overflow) = u.sub(Mul::new(v, q_hat), j, n); // D4 - u = u_new; - - if overflow { // D5 - unlikely, probability of this being true is ~ 2 / b where b is the digit base (i.e. `Digit::MAX + 1`) - q_hat -= 1; - u = u.add(v, j, n); } - q.digits[j] = q_hat; } - (q, u.shr(shift)) + 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 (u_new, overflow) = u.sub(Mul::new(v, q_hat), j, n); // D4 + u = u_new; + + if overflow { + // D5 - unlikely, probability of this being true is ~ 2 / b where b is the digit base (i.e. `Digit::MAX + 1`) + q_hat -= 1; + u = u.add(v, j, n); } + q.digits[j] = q_hat; } - }; + (q, u.shr(shift)) + } } - -crate::macro_impl!(div_impl); \ No newline at end of file diff --git a/src/buint/endian.rs b/src/buint/endian.rs index f3d96ad..7205fe5 100644 --- a/src/buint/endian.rs +++ b/src/buint/endian.rs @@ -1,300 +1,295 @@ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit}; 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() - } +#[doc = doc::endian::impl_desc!(BUintD8)] +impl BUintD8 { + #[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) + } - /// 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 - /// - /// ``` - /// 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 digit_bytes = [0u8; digit::$Digit::BYTES as usize]; - let init_index = len - digit::$Digit::BYTES as usize; - let mut j = init_index; - while j < slice.len() { - digit_bytes[j - init_index] = slice[j - (i << digit::$Digit::BYTE_SHIFT)]; - j += 1; - } - 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 + /// + /// ``` + /// 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::BYTE_SHIFT; + while i < exact { + let mut digit_bytes = [0u8; digit::BYTES as usize]; + let init_index = len - digit::BYTES as usize; + let mut j = init_index; + while j < slice.len() { + digit_bytes[j - init_index] = slice[j - (i << digit::BYTE_SHIFT)]; + j += 1; } - - /// 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 - /// - /// ``` - /// 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 digit_bytes = [0u8; digit::$Digit::BYTES as usize]; - let init_index = i << digit::$Digit::BYTE_SHIFT; - let mut j = init_index; - while j < init_index + digit::$Digit::BYTES as usize { - digit_bytes[j - init_index] = slice[j]; - j += 1; - } - 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) - } + 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::BYTES as usize - 1); + if rem == 0 { + Some(out) + } else { + let mut last_digit_bytes = [0; digit::BYTES as usize]; + let mut j = 0; + while j < rem { + last_digit_bytes[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) + } + } - #[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; Self::BYTES_USIZE] { - let mut bytes = [0; Self::BYTES_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 + /// 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 + /// + /// ``` + /// 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::BYTE_SHIFT; + while i < exact { + let mut digit_bytes = [0u8; digit::BYTES as usize]; + let init_index = i << digit::BYTE_SHIFT; + let mut j = init_index; + while j < init_index + digit::BYTES as usize { + digit_bytes[j - init_index] = slice[j]; + j += 1; + } + 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::BYTES as usize - 1) == 0 { + Some(out) + } else { + let mut last_digit_bytes = [0; digit::BYTES as usize]; + let addition = exact << 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_le_bytes!(U)] - #[doc = doc::requires_feature!("nightly")] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn to_le_bytes(self) -> [u8; Self::BYTES_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; Self::BYTES_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_be_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_be_bytes(self) -> [u8; Self::BYTES_USIZE] { + let mut bytes = [0; Self::BYTES_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::BYTES as usize { + bytes[(i << digit::BYTE_SHIFT) + j] = digit_bytes[j]; + j += 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; Self::BYTES_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_le_bytes!(U)] + #[doc = doc::requires_feature!("nightly")] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn to_le_bytes(self) -> [u8; Self::BYTES_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; Self::BYTES_USIZE]; + let mut i = 0; + while i < N { + let digit_bytes = self.digits[i].to_le_bytes(); + let mut j = 0; + while j < digit::BYTES as usize { + bytes[(i << digit::BYTE_SHIFT) + j] = digit_bytes[j]; + j += 1; } + i += 1; + } + 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; Self::BYTES_USIZE]) -> Self { - let mut out = Self::ZERO; - // let arr_ptr = bytes.as_ptr(); - let mut i = 0; - while i < N { - let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize]; - let init_index = N * digit::$Digit::BYTES as usize - digit::$Digit::BYTES as usize; - let mut j = init_index; - while j < N * digit::$Digit::BYTES as usize { - digit_bytes[j - init_index] = bytes[j - (i << digit::$Digit::BYTE_SHIFT)]; - j += 1; - } - out.digits[i] = $Digit::from_be_bytes(digit_bytes); - i += 1; - } - out + #[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; Self::BYTES_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; Self::BYTES_USIZE]) -> Self { + let mut out = Self::ZERO; + // let arr_ptr = bytes.as_ptr(); + let mut i = 0; + while i < N { + let mut digit_bytes = [0u8; digit::BYTES as usize]; + let init_index = N * digit::BYTES as usize - digit::BYTES as usize; + let mut j = init_index; + while j < N * digit::BYTES as usize { + digit_bytes[j - init_index] = bytes[j - (i << digit::BYTE_SHIFT)]; + j += 1; } + 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; Self::BYTES_USIZE]) -> Self { - let mut out = Self::ZERO; - // let arr_ptr = bytes.as_ptr(); - let mut i = 0; - while i < N { - let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize]; - let init_index = i << digit::$Digit::BYTE_SHIFT; - let mut j = init_index; - while j < init_index + digit::$Digit::BYTES as usize { - digit_bytes[j - init_index] = bytes[j]; - j += 1; - } - 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; Self::BYTES_USIZE]) -> Self { + let mut out = Self::ZERO; + // let arr_ptr = bytes.as_ptr(); + let mut i = 0; + while i < N { + let mut digit_bytes = [0u8; digit::BYTES as usize]; + let init_index = i << digit::BYTE_SHIFT; + let mut j = init_index; + while j < init_index + digit::BYTES as usize { + digit_bytes[j - init_index] = bytes[j]; + j += 1; } + 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; Self::BYTES_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; Self::BYTES_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) + } - pub(crate) const BYTES_USIZE: usize = N * digit::$Digit::BYTES as usize; - } - }; + pub(crate) const BYTES_USIZE: usize = N * digit::BYTES as usize; } #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::{test_bignum, types::utest}; +mod tests { + use crate::test::{test_bignum, types::*}; crate::int::endian::tests!(utest); } - -crate::macro_impl!(endian); diff --git a/src/buint/fmt.rs b/src/buint/fmt.rs index 3202c69..dd5594e 100644 --- a/src/buint/fmt.rs +++ b/src/buint/fmt.rs @@ -1,115 +1,104 @@ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit}; use alloc::string::String; 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)?; - } +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)?; } - f.pad_integral( - true, - $prefix, - if format_string.is_empty() { - "0" - } else { - &format_string - }, - ) + } 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 { - /*#[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - f.pad_integral(true, "0b", &self.to_str_radix(2)) - }*/ - fmt_method!("{:b}", "{:01$b}", digit::$Digit::BITS as usize, "0b"); - } +impl Binary for BUintD8 { + /*#[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + f.pad_integral(true, "0b", &self.to_str_radix(2)) + }*/ + fmt_method!("{:b}", "{:01$b}", 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 BUintD8 { + #[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 { - f.pad_integral(true, "", &self.to_str_radix(10)) - } - } +impl Display for BUintD8 { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + f.pad_integral(true, "", &self.to_str_radix(10)) + } +} - macro_rules! exp_fmt { - ($e: expr) => { - #[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - let decimal_str = self.to_str_radix(10); - let buf = if decimal_str == "0" { - format!("{}{}0", 0, $e) - } else { - let exp = decimal_str.len() - 1; - let decimal_str = decimal_str.trim_end_matches('0'); - if decimal_str.len() == 1 { - format!("{}{}{}", &decimal_str[0..1], $e, exp) - } else { - format!( - "{}.{}{}{}", - &decimal_str[0..1], - &decimal_str[1..], - $e, - exp - ) - } - }; - f.pad_integral(true, "", &buf) +macro_rules! exp_fmt { + ($e: expr) => { + #[inline] + fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { + let decimal_str = self.to_str_radix(10); + let buf = if decimal_str == "0" { + format!("{}{}0", 0, $e) + } else { + let exp = decimal_str.len() - 1; + let decimal_str = decimal_str.trim_end_matches('0'); + if decimal_str.len() == 1 { + format!("{}{}{}", &decimal_str[0..1], $e, exp) + } else { + format!("{}.{}{}{}", &decimal_str[0..1], &decimal_str[1..], $e, exp) } }; + f.pad_integral(true, "", &buf) } + }; +} - impl LowerExp for $BUint { - exp_fmt!("e"); - } +impl LowerExp for BUintD8 { + exp_fmt!("e"); +} - impl LowerHex for $BUint { - fmt_method!("{:x}", "{:01$x}", digit::$Digit::HEX_PADDING, "0x"); - } +impl LowerHex for BUintD8 { + fmt_method!("{:x}", "{:01$x}", 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 BUintD8 { + #[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 BUintD8 { + exp_fmt!("E"); +} - impl UpperHex for $BUint { - fmt_method!("{:X}", "{:01$X}", digit::$Digit::HEX_PADDING, "0x"); - } - }; +impl UpperHex for BUintD8 { + fmt_method!("{:X}", "{:01$X}", digit::HEX_PADDING, "0x"); } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { crate::int::fmt::tests!(utest); } - -crate::macro_impl!(fmt); \ No newline at end of file diff --git a/src/buint/mask.rs b/src/buint/mask.rs index fa20d8f..9afc2fc 100644 --- a/src/buint/mask.rs +++ b/src/buint/mask.rs @@ -1,18 +1,18 @@ // macro_rules! mask { -// ($BUint: ident, $BInt: ident, $Digit: ident) => { -// impl $BUint { +// (BUintD8: ident, BIntD8: ident, Digit: ident) => { +// impl BUintD8 { // #[inline] // pub(crate) const fn least_significant_n_bits(self, n: ExpType) -> Self { // let mut mask = Self::ZERO; -// let mut digit_index = n as usize >> digit::$Digit::BIT_SHIFT; +// let mut digit_index = n as usize >> digit::BIT_SHIFT; // let mut i = 0; // while i < digit_index { -// mask.digits[i] = $Digit::MAX; +// mask.digits[i] = Digit::MAX; // i += 1; // } - + // self.bitand(mask) // } // } // }; -// } \ No newline at end of file +// } diff --git a/src/buint/mod.rs b/src/buint/mod.rs index f35c042..a5e64fb 100644 --- a/src/buint/mod.rs +++ b/src/buint/mod.rs @@ -1,6 +1,6 @@ +use crate::{digit, Digit, BIntD8}; use crate::errors::{self, option_expect}; -use crate::digit; use crate::doc; use crate::ExpType; // use core::mem::MaybeUninit; @@ -21,633 +21,630 @@ use core::default::Default; use core::iter::{Iterator, Product, Sum}; -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)] - - #[derive(Clone, Copy, Hash, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] - #[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize, BorshSchema))] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - #[cfg_attr(feature = "valuable", derive(valuable::Valuable))] - #[repr(transparent)] - pub struct $BUint { - #[cfg_attr(feature = "serde", serde(with = "BigArray"))] - pub(crate) digits: [$Digit; N], - } +/// 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!(BUintD8)] +#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "borsh", + derive(BorshSerialize, BorshDeserialize, BorshSchema) +)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "valuable", derive(valuable::Valuable))] +#[repr(transparent)] +pub struct BUintD8 { + #[cfg_attr(feature = "serde", serde(with = "BigArray"))] + pub(crate) digits: [Digit; N], +} - #[cfg(feature = "zeroize")] - impl zeroize::DefaultIsZeroes for $BUint {} - - 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 - } +#[cfg(feature = "zeroize")] +impl zeroize::DefaultIsZeroes for BUintD8 {} + +impl BUintD8 { + #[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::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::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::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::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 - } + #[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 + } - #[doc = doc::cast_signed!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn cast_signed(self) -> $BInt { - $BInt::::from_bits(self) - } + #[doc = doc::cast_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn cast_signed(self) -> BIntD8 { + BIntD8::::from_bits(self) + } - #[inline] - const unsafe fn rotate_digits_left(self, n: usize) -> Self { - let mut out = Self::ZERO; - let mut i = n; - while i < N { - out.digits[i] = self.digits[i - n]; - i += 1; - } - let init_index = N - n; - let mut i = init_index; - while i < N { - out.digits[i - init_index] = self.digits[i]; - i += 1; - } - - out - } + #[inline] + const unsafe fn rotate_digits_left(self, n: usize) -> Self { + let mut out = Self::ZERO; + let mut i = n; + while i < N { + out.digits[i] = self.digits[i - n]; + i += 1; + } + let init_index = N - n; + let mut i = init_index; + while i < N { + out.digits[i - init_index] = self.digits[i]; + i += 1; + } - #[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; + out + } - let mut out = self.rotate_digits_left(digit_shift); + #[inline] + const unsafe fn unchecked_rotate_left(self, rhs: ExpType) -> Self { + let digit_shift = (rhs >> digit::BIT_SHIFT) as usize; + let bit_shift = rhs & digit::BITS_MINUS_1; - if bit_shift != 0 { - let carry_shift = digit::$Digit::BITS - bit_shift; - let mut carry = 0; + let mut out = self.rotate_digits_left(digit_shift); - 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; - } + if bit_shift != 0 { + let carry_shift = digit::BITS - bit_shift; + let mut carry = 0; - out + 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; + } - const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType; + out + } - #[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) - } - } + const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType; - #[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) - } - } + #[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) } + } - 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::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) } + } - #[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 - } + 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::pow!(U 256)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn pow(self, exp: ExpType) -> Self { - #[cfg(debug_assertions)] - return self.strict_pow(exp); + #[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 + } - #[cfg(not(debug_assertions))] - self.wrapping_pow(exp) - } + #[doc = doc::pow!(U 256)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn pow(self, exp: ExpType) -> Self { + #[cfg(debug_assertions)] + return self.strict_pow(exp); - #[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) - } + #[cfg(not(debug_assertions))] + self.wrapping_pow(exp) + } + #[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::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::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::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::midpoint!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn midpoint(self, rhs: Self) -> Self { - // see section 2.5: Average of Two Integers in Hacker's Delight - self.bitand(rhs).add(self.bitxor(rhs).shr(1)) - } + #[doc = doc::midpoint!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn midpoint(self, rhs: Self) -> Self { + // see section 2.5: Average of Two Integers in Hacker's Delight + self.bitand(rhs).add(self.bitxor(rhs).shr(1)) + } - #[doc = doc::ilog2!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn ilog2(self) -> ExpType { - option_expect!( - self.checked_ilog2(), - errors::err_msg!(errors::non_positive_log_message!()) - ) - } + #[doc = doc::ilog2!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn ilog2(self) -> ExpType { + option_expect!( + self.checked_ilog2(), + errors::err_msg!(errors::non_positive_log_message!()) + ) + } - #[doc = doc::ilog10!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn ilog10(self) -> ExpType { - option_expect!( - self.checked_ilog10(), - errors::err_msg!(errors::non_positive_log_message!()) - ) - } + #[doc = doc::ilog10!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn ilog10(self) -> ExpType { + option_expect!( + self.checked_ilog10(), + errors::err_msg!(errors::non_positive_log_message!()) + ) + } - #[doc = doc::ilog!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn ilog(self, base: Self) -> ExpType { - if base.le(&Self::ONE) { - panic!("{}", errors::err_msg!(errors::invalid_log_base!())); - } - option_expect!( - self.checked_ilog(base), errors::err_msg!(errors::non_positive_log_message!()) - ) - } + #[doc = doc::ilog!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn ilog(self, base: Self) -> ExpType { + if base.le(&Self::ONE) { + panic!("{}", errors::err_msg!(errors::invalid_log_base!())); + } + option_expect!( + self.checked_ilog(base), + errors::err_msg!(errors::non_positive_log_message!()) + ) + } - #[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) - } - } + #[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) + } + } - #[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::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_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) - } - } + #[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(self, rhs: ExpType) -> Self { - 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.saturating_sub(digit_shift); // TODO: use unchecked_ methods from primitives when these are stablised and constified - - 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 = self.digits[i - digit_shift]; - out.digits[i] = (current_digit << bit_shift) | carry; - carry = current_digit >> carry_shift; - i += 1; - } - } else { - let mut i = digit_shift; - while i < N { // we start i at digit_shift, not 0, since the compiler can elide bounds checks when i < N - out.digits[i] = self.digits[i - digit_shift]; - i += 1; - } - } - - out - } - - #[inline] - pub(crate) const unsafe fn unchecked_shr_pad_internal(self, rhs: ExpType) -> Self { - let mut out = if NEG { - $BUint::MAX - } else { - $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.saturating_sub(digit_shift); // TODO: use unchecked_ methods from primitives when these are stablised and constified - - if bit_shift != 0 { - let carry_shift = digit::$Digit::BITS - bit_shift; - let mut carry = 0; - - let mut i = digit_shift; - while i < N { // we use an increment while loop because the compiler can elide the array bounds check, which results in big performance gains - let index = N - 1 - i; - let current_digit = self.digits[index + digit_shift]; - out.digits[index] = (current_digit >> bit_shift) | carry; - carry = current_digit << carry_shift; - i += 1; - } - - if NEG { - out.digits[num_copies - 1] |= $Digit::MAX << carry_shift; - } - } else { - let mut i = digit_shift; - while i < N { // we start i at digit_shift, not 0, since the compiler can elide bounds checks when i < N - out.digits[i - digit_shift] = self.digits[i]; - i += 1; - } - } - - out +impl BUintD8 { + #[inline] + pub(crate) const unsafe fn unchecked_shl_internal(self, rhs: ExpType) -> Self { + let mut out = BUintD8::ZERO; + let digit_shift = (rhs >> digit::BIT_SHIFT) as usize; + let bit_shift = rhs & digit::BITS_MINUS_1; + + // let num_copies = N.saturating_sub(digit_shift); // TODO: use unchecked_ methods from primitives when these are stablised and constified + + if bit_shift != 0 { + let carry_shift = digit::BITS - bit_shift; + let mut carry = 0; + + let mut i = digit_shift; + while i < N { + let current_digit = self.digits[i - digit_shift]; + out.digits[i] = (current_digit << bit_shift) | carry; + carry = current_digit >> carry_shift; + i += 1; + } + } else { + let mut i = digit_shift; + while i < N { + // we start i at digit_shift, not 0, since the compiler can elide bounds checks when i < N + out.digits[i] = self.digits[i - digit_shift]; + i += 1; } + } - pub(crate) const unsafe fn unchecked_shr_internal(u: $BUint, rhs: ExpType) -> $BUint { - Self::unchecked_shr_pad_internal::(u, rhs) - } + out + } - #[doc = doc::bits!(U 256)] - #[must_use] - #[inline] - pub const fn bits(&self) -> ExpType { - Self::BITS as ExpType - self.leading_zeros() + #[inline] + pub(crate) const unsafe fn unchecked_shr_pad_internal( + self, + rhs: ExpType, + ) -> Self { + let mut out = if NEG { BUintD8::MAX } else { BUintD8::ZERO }; + let digit_shift = (rhs >> digit::BIT_SHIFT) as usize; + let bit_shift = rhs & digit::BITS_MINUS_1; + + let num_copies = N.saturating_sub(digit_shift); // TODO: use unchecked_ methods from primitives when these are stablised and constified + + if bit_shift != 0 { + let carry_shift = digit::BITS - bit_shift; + let mut carry = 0; + + let mut i = digit_shift; + while i < N { + // we use an increment while loop because the compiler can elide the array bounds check, which results in big performance gains + let index = N - 1 - i; + let current_digit = self.digits[index + digit_shift]; + out.digits[index] = (current_digit >> bit_shift) | carry; + carry = current_digit << carry_shift; + i += 1; + } + + if NEG { + out.digits[num_copies - 1] |= Digit::MAX << carry_shift; + } + } else { + let mut i = digit_shift; + while i < N { + // we start i at digit_shift, not 0, since the compiler can elide bounds checks when i < N + out.digits[i - digit_shift] = self.digits[i]; + i += 1; } + } - #[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 - } + out + } - #[doc = doc::set_bit!(U 256)] - #[inline] - pub fn set_bit(&mut self, index: ExpType, value: bool) { - let digit = &mut self.digits[index as usize >> digit::$Digit::BIT_SHIFT]; - let shift = index & digit::$Digit::BITS_MINUS_1; - if value { - *digit |= (1 << shift); - } else { - *digit &= !(1 << shift); - } - } + pub(crate) const unsafe fn unchecked_shr_internal(u: BUintD8, rhs: ExpType) -> BUintD8 { + Self::unchecked_shr_pad_internal::(u, rhs) + } - /// 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 - } + #[doc = doc::bits!(U 256)] + #[must_use] + #[inline] + pub const fn bits(&self) -> ExpType { + Self::BITS as ExpType - self.leading_zeros() + } - // #[inline(always)] - // pub(crate) const fn digit(&self, index: usize) -> $Digit { - // self.digits[index] - // } + #[doc = doc::bit!(U 256)] + #[must_use] + #[inline] + pub const fn bit(&self, index: ExpType) -> bool { + let digit = self.digits[index as usize >> digit::BIT_SHIFT]; + digit & (1 << (index & digit::BITS_MINUS_1)) != 0 + } - /// 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 - } + #[doc = doc::set_bit!(U 256)] + #[inline] + pub fn set_bit(&mut self, index: ExpType, value: bool) { + let digit = &mut self.digits[index as usize >> digit::BIT_SHIFT]; + let shift = index & digit::BITS_MINUS_1; + if value { + *digit |= (1 << shift); + } else { + *digit &= !(1 << shift); + } + } - /// Returns the digits stored in `self` as a mutable array. Digits are little endian (least significant digit first). - #[must_use] - #[inline(always)] - pub fn digits_mut(&mut self) -> &mut [$Digit; N] { - &mut self.digits - } + /// 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::BIT_SHIFT] = + 1 << (power & (digit::BITS - 1)); + out + } - /// 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 } - } + // #[inline(always)] + // pub(crate) const fn digit(&self, index: usize) -> Digit { + // self.digits[index] + // } - /// 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 - } + /// 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 + } - #[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 - } + /// Returns the digits stored in `self` as a mutable array. Digits are little endian (least significant digit first). + #[must_use] + #[inline(always)] + pub fn digits_mut(&mut self) -> &mut [Digit; N] { + &mut self.digits + } - #[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 - } + /// 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 } + } - #[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 - } + /// 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 + } - #[allow(unused)] - #[inline] - fn square(self) -> Self { - // TODO: optimise this method, this will make exponentiation by squaring faster - self * self + #[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 + } - impl Default for $BUint { - #[doc = doc::default!()] - #[inline] - fn default() -> Self { - Self::ZERO - } + #[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; } - - impl Product for $BUint { - #[inline] - fn product>(iter: I) -> Self { - iter.fold(Self::ONE, |a, b| a * b) + let mut i = 1; + while i < N { + if (&self.digits)[i] != 0 { + return false; } + i += 1; } + true + } - impl<'a, const N: usize> Product<&'a Self> for $BUint { - #[inline] - fn product>(iter: I) -> Self { - iter.fold(Self::ONE, |a, b| a * b) + #[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 + } - impl Sum for $BUint { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::ZERO, |a, b| a + b) - } - } + #[allow(unused)] + #[inline] + fn square(self) -> Self { + // TODO: optimise this method, this will make exponentiation by squaring faster + self * self + } +} - impl<'a, const N: usize> Sum<&'a Self> for $BUint { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::ZERO, |a, b| a + b) - } - } +impl Default for BUintD8 { + #[doc = doc::default!()] + #[inline] + fn default() -> Self { + Self::ZERO + } +} - #[cfg(any(test, feature = "quickcheck"))] - impl quickcheck::Arbitrary for $BUint { - fn arbitrary(g: &mut quickcheck::Gen) -> Self { - let mut out = Self::ZERO; - for digit in out.digits.iter_mut() { - *digit = <$Digit as quickcheck::Arbitrary>::arbitrary(g); - } - out - } +impl Product for BUintD8 { + #[inline] + fn product>(iter: I) -> Self { + iter.fold(Self::ONE, |a, b| a * b) + } +} + +impl<'a, const N: usize> Product<&'a Self> for BUintD8 { + #[inline] + fn product>(iter: I) -> Self { + iter.fold(Self::ONE, |a, b| a * b) + } +} + +impl Sum for BUintD8 { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |a, b| a + b) + } +} + +impl<'a, const N: usize> Sum<&'a Self> for BUintD8 { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |a, b| a + b) + } +} + +#[cfg(any(test, feature = "quickcheck"))] +impl quickcheck::Arbitrary for BUintD8 { + fn arbitrary(g: &mut quickcheck::Gen) -> Self { + let mut out = Self::ZERO; + for digit in out.digits.iter_mut() { + *digit = ::arbitrary(g); } - }; + out + } } #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::{debug_skip, test_bignum, types::utest}; +mod tests { + use crate::test::{debug_skip, test_bignum, types::*}; crate::int::tests!(utest); @@ -691,9 +688,9 @@ crate::test::all_digit_tests! { assert!(UTEST::ONE.is_one()); assert!(!UTEST::MAX.is_one()); assert!(!UTEST::ZERO.is_one()); - let mut digits = *super::BUint::<2>::MAX.digits(); + let mut digits = *super::BUintD8::<2>::MAX.digits(); digits[0] = 1; - let b = super::BUint::<2>::from_digits(digits); + let b = super::BUintD8::<2>::from_digits(digits); assert!(!b.is_one()); } @@ -726,8 +723,6 @@ crate::test::all_digit_tests! { } } -crate::macro_impl!(mod_impl); - mod bigint_helpers; pub mod cast; mod checked; diff --git a/src/buint/mul.rs b/src/buint/mul.rs index c4b8562..8bed84f 100644 --- a/src/buint/mul.rs +++ b/src/buint/mul.rs @@ -1,43 +1,40 @@ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit}; -macro_rules! mul { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl $BUint { - #[inline] - pub(super) const fn long_mul(self, rhs: Self) -> (Self, bool) { - let mut overflow = false; - let mut out = Self::ZERO; - let mut carry: $Digit; +impl BUintD8 { + #[inline] + pub(super) const fn long_mul(self, rhs: Self) -> (Self, bool) { + let mut overflow = false; + let mut out = Self::ZERO; + let mut carry: Digit; - let mut i = 0; - while i < N { - carry = 0; - let mut j = 0; - while j < N { - let index = i + j; - if index < N { - let (prod, c) = digit::$Digit::carrying_mul( - self.digits[i], - rhs.digits[j], - carry, - out.digits[index], - ); - out.digits[index] = prod; - carry = c; - } else if self.digits[i] != 0 && rhs.digits[j] != 0 { - overflow = true; - break; - } - j += 1; - } - if carry != 0 { - overflow = true; - } - i += 1; + let mut i = 0; + while i < N { + carry = 0; + let mut j = 0; + while j < N { + let index = i + j; + if index < N { + let (prod, c) = digit::carrying_mul( + self.digits[i], + rhs.digits[j], + carry, + out.digits[index], + ); + out.digits[index] = prod; + carry = c; + } else if self.digits[i] != 0 && rhs.digits[j] != 0 { + overflow = true; + break; } - (out, overflow) + j += 1; } + if carry != 0 { + overflow = true; + } + i += 1; } + (out, overflow) } } @@ -53,7 +50,7 @@ macro_rules! mul { // let z0 = karatsuba(a, b, end_index, mid_index); // // let d1 = abs_diff(x0, x1); // // let d2 = abs_diff(y0, y1); -// // +// // // // let a = karatsuba((x0 - x1)(y1 - y0)) // // let z1 = a + z2 @@ -75,5 +72,3 @@ macro_rules! mul { // let (a1karat_widening(x1, y1); // karat_widening(x0, y0); // } - -crate::macro_impl!(mul); \ No newline at end of file diff --git a/src/buint/numtraits.rs b/src/buint/numtraits.rs index 5a13eac..6828c52 100644 --- a/src/buint/numtraits.rs +++ b/src/buint/numtraits.rs @@ -1,13 +1,16 @@ +use super::BUintD8; +use crate::{digit, Digit}; + macro_rules! to_int { - { $Digit: ident; $($name: ident -> $int: ty), * } => { + { $($name: ident -> $int: ty), * } => { $( #[inline] fn $name(&self) -> Option<$int> { let mut out = 0; let mut i = 0; - if $Digit::BITS > <$int>::BITS { + if Digit::BITS > <$int>::BITS { let small = self.digits[i] as $int; - let trunc = small as $Digit; + let trunc = small as Digit; if self.digits[i] != trunc { return None; } @@ -15,7 +18,7 @@ macro_rules! to_int { i = 1; } else { loop { - let shift = i << crate::digit::$Digit::BIT_SHIFT; + let shift = i << crate::digit::BIT_SHIFT; if i >= N || shift >= <$int>::BITS as usize { break; } @@ -53,380 +56,401 @@ use crate::buint::cast::{decode_f32, decode_f64}; use crate::ExpType; use num_integer::{Integer, Roots}; use num_traits::{ - AsPrimitive, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, - CheckedShr, CheckedSub, CheckedEuclid, Euclid, FromPrimitive, MulAdd, MulAddAssign, Num, One, /*ConstOne,*/ Pow, PrimInt, - Saturating, SaturatingAdd, SaturatingMul, SaturatingSub, ToPrimitive, Unsigned, WrappingAdd, - WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, Zero, //ConstZero + AsPrimitive, + Bounded, + CheckedAdd, + CheckedDiv, + CheckedEuclid, + CheckedMul, + CheckedNeg, + CheckedRem, + CheckedShl, + CheckedShr, + CheckedSub, + Euclid, + FromPrimitive, + MulAdd, + MulAddAssign, + Num, + One, + /*ConstOne,*/ Pow, + PrimInt, + Saturating, + SaturatingAdd, + SaturatingMul, + SaturatingSub, + ToPrimitive, + Unsigned, + WrappingAdd, + WrappingMul, + WrappingNeg, + WrappingShl, + WrappingShr, + WrappingSub, + Zero, //ConstZero }; use crate::cast::CastFrom; use crate::int::numtraits::num_trait_impl; -macro_rules! numtraits { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - crate::int::numtraits::impls!($BUint, $BUint, $BInt, $Digit); - - macro_rules! from_float { - ($method: ident, $float: ty, $decoder: ident, $mant_bits: ident) => { - #[inline] - fn $method(f: $float) -> Option { - if !f.is_finite() { - return None; - } - if f == 0.0 { - return Some(Self::ZERO); - } - if f.is_sign_negative() { - return None; - } - let (mut mant, exp) = $decoder(f); - if exp.is_negative() { - mant = mant.checked_shr((-exp) as ExpType).unwrap_or(0); - if $mant_bits(mant) > Self::BITS { - return None; - } - Some(Self::cast_from(mant)) - } else { - if $mant_bits(mant) + exp as ExpType > Self::BITS { - return None; - } - Some(Self::cast_from(mant) << exp) - } - } - }; - } +crate::int::numtraits::impls!(BUintD8); - impl FromPrimitive for $BUint { - #[inline] - fn from_u64(int: u64) -> Option { - const UINT_BITS: usize = u64::BITS as usize; - let mut out = $BUint::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 { - if i < N { - out.digits[i] = d; - } else { - return None; - } - } - i += 1; - } - Some(out) +macro_rules! from_float { + ($method: ident, $float: ty, $decoder: ident, $mant_bits: ident) => { + #[inline] + fn $method(f: $float) -> Option { + if !f.is_finite() { + return None; } - - #[inline] - fn from_i64(int: i64) -> Option { - match u64::try_from(int) { - Ok(int) => Self::from_u64(int), - _ => None, - } + if f == 0.0 { + return Some(Self::ZERO); } - - #[inline] - fn from_u128(int: u128) -> Option { - const UINT_BITS: usize = u128::BITS as usize; - let mut out = $BUint::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 { - if i < N { - out.digits[i] = d; - } else { - return None; - } - } - i += 1; - } - Some(out) + if f.is_sign_negative() { + return None; } - - #[inline] - fn from_i128(n: i128) -> Option { - match u128::try_from(n) { - Ok(n) => Self::from_u128(n), - _ => None, + let (mut mant, exp) = $decoder(f); + if exp.is_negative() { + mant = mant.checked_shr((-exp) as ExpType).unwrap_or(0); + if $mant_bits(mant) > Self::BITS { + return None; + } + Some(Self::cast_from(mant)) + } else { + if $mant_bits(mant) + exp as ExpType > Self::BITS { + return None; } + Some(Self::cast_from(mant) << exp) } - - // TODO: replace this with code from the cast/float module - from_float!(from_f32, f32, decode_f32, u32_bits); - from_float!(from_f64, f64, decode_f64, u64_bits); } + }; +} - 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 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; - } - 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); - } - 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()); - } +impl FromPrimitive for BUintD8 { + #[inline] + fn from_u64(int: u64) -> Option { + const UINT_BITS: usize = u64::BITS as usize; + let mut out = BUintD8::ZERO; + let mut i = 0; + while i << crate::digit::BIT_SHIFT < UINT_BITS { + let d = (int >> (i << crate::digit::BIT_SHIFT)) as Digit; + if d != 0 { + if i < N { + out.digits[i] = d; + } else { + return None; } } - - #[inline] - fn lcm(&self, other: &Self) -> Self { - if self.is_zero() || other.is_zero() { - Self::ZERO + i += 1; + } + Some(out) + } + + #[inline] + fn from_i64(int: i64) -> Option { + match u64::try_from(int) { + Ok(int) => Self::from_u64(int), + _ => None, + } + } + + #[inline] + fn from_u128(int: u128) -> Option { + const UINT_BITS: usize = u128::BITS as usize; + let mut out = BUintD8::ZERO; + let mut i = 0; + while i << crate::digit::BIT_SHIFT < UINT_BITS { + let d = (int >> (i << crate::digit::BIT_SHIFT)) as Digit; + if d != 0 { + if i < N { + out.digits[i] = d; } else { - self.div_floor(&self.gcd(other)) * *other + return None; } } + i += 1; + } + Some(out) + } + + #[inline] + fn from_i128(n: i128) -> Option { + match u128::try_from(n) { + Ok(n) => Self::from_u128(n), + _ => None, + } + } - #[inline] - fn divides(&self, other: &Self) -> bool { - self.is_multiple_of(other) - } + // TODO: replace this with code from the cast/float module + from_float!(from_f32, f32, decode_f32, u32_bits); + from_float!(from_f64, f64, decode_f64, u64_bits); +} - #[inline] - fn is_multiple_of(&self, other: &Self) -> bool { - self.mod_floor(other).is_zero() - } +impl Integer for BUintD8 { + #[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 { + // 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; + } + 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); + } - #[inline] - fn is_even(&self) -> bool { - self.digits[0] & 1 == 0 + 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); } - - #[inline] - fn is_odd(&self) -> bool { - self.digits[0] & 1 == 1 + a -= b; + if a.is_zero() { + return unsafe { Self::unchecked_shl_internal(b, b_tz) }; } - - #[inline] - fn div_rem(&self, rhs: &Self) -> (Self, Self) { - Self::div_rem(*self, *rhs) + unsafe { + a = Self::unchecked_shr_internal(a, a.trailing_zeros()); } } + } + + #[inline] + fn lcm(&self, other: &Self) -> Self { + if self.is_zero() || other.is_zero() { + Self::ZERO + } else { + 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.digits[0] & 1 == 0 + } + + #[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) + } +} - impl PrimInt for $BUint { - crate::int::numtraits::prim_int_methods!(); +impl PrimInt for BUintD8 { + 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 { + (crate::BIntD8::from_bits(self) >> n).to_bits() // TODO: need to change this if we add "signed-int" as a feature + } - #[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 { + ($self: ident) => { + if N == 0 { + return *$self; + } + if $self.last_digit_index() == 0 { + let d = $self.digits[0]; + if d == 0 || d == 1 { + return *$self; } } + }; +} - macro_rules! check_zero_or_one { - ($self: ident) => { - if N == 0 { - return *$self; - } - if $self.last_digit_index() == 0 { - let d = $self.digits[0]; - if d == 0 || d == 1 { - return *$self; - } - } +/* +The `fixpoint` function and the implementation of `Roots` below are adapted from the Rust `num_bigint` library, https://docs.rs/num-bigint/latest/num_bigint/, modified under the MIT license. The changes are released under either the MIT license or the Apache License 2.0, as described in the README. See LICENSE-MIT or LICENSE-APACHE at the project root. + +The appropriate copyright notice for the `num_bigint` code is given below: +Copyright (c) 2014 The Rust Project Developers + +The original license file and copyright notice for `num_bigint` can be found in this project's root at licenses/LICENSE-num-bigint. +*/ + +impl BUintD8 { + #[inline] + fn fixpoint(mut self, max_bits: ExpType, f: F) -> Self + where + F: Fn(Self) -> Self, + { + let mut xn = f(self); + while self < xn { + self = if xn.bits() > max_bits { + Self::power_of_two(max_bits) + } else { + xn }; + xn = f(self); } + while self > xn { + self = xn; + xn = f(self); + } + self + } +} - /* - The `fixpoint` function and the implementation of `Roots` below are adapted from the Rust `num_bigint` library, https://docs.rs/num-bigint/latest/num_bigint/, modified under the MIT license. The changes are released under either the MIT license or the Apache License 2.0, as described in the README. See LICENSE-MIT or LICENSE-APACHE at the project root. - - The appropriate copyright notice for the `num_bigint` code is given below: - Copyright (c) 2014 The Rust Project Developers - - The original license file and copyright notice for `num_bigint` can be found in this project's root at licenses/LICENSE-num-bigint. - */ +impl Roots for BUintD8 { + #[inline] + fn sqrt(&self) -> Self { + check_zero_or_one!(self); - impl $BUint { - #[inline] - fn fixpoint(mut self, max_bits: ExpType, f: F) -> Self - where - F: Fn(Self) -> Self, - { - let mut xn = f(self); - while self < xn { - self = if xn.bits() > max_bits { - Self::power_of_two(max_bits) - } else { - xn - }; - xn = f(self); - } - while self > xn { - self = xn; - xn = f(self); - } - self - } + #[cfg(not(test))] + // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested + if let Some(n) = self.to_u128() { + return n.sqrt().into(); } - - impl Roots for $BUint { - #[inline] - fn sqrt(&self) -> Self { + let bits = self.bits(); + let max_bits = bits / 2 + 1; + + let guess = Self::power_of_two(max_bits); + guess.fixpoint(max_bits, |s| { + let q = self / s; + let t = s + q; + t >> 1 + }) + } + + #[inline] + fn cbrt(&self) -> Self { + check_zero_or_one!(self); + + #[cfg(not(test))] + // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested + if let Some(n) = self.to_u128() { + return n.cbrt().into(); + } + let bits = self.bits(); + let max_bits = bits / 3 + 1; + + let guess = Self::power_of_two(max_bits); + guess.fixpoint(max_bits, |s| { + let q = self / (s * s); + let t: Self = (s << 1) + q; + t.div_rem_digit(3).0 + }) + } + + #[inline] + fn nth_root(&self, n: u32) -> Self { + match n { + 0 => panic!(crate::errors::err_msg!("attempt to calculate zeroth root")), + 1 => *self, + 2 => self.sqrt(), + 3 => self.cbrt(), + _ => { check_zero_or_one!(self); #[cfg(not(test))] // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested - if let Some(n) = self.to_u128() { - return n.sqrt().into(); + if let Some(x) = self.to_u128() { + return x.nth_root(n).into(); } let bits = self.bits(); - let max_bits = bits / 2 + 1; - - let guess = Self::power_of_two(max_bits); - guess.fixpoint(max_bits, |s| { - let q = self / s; - let t = s + q; - t >> 1 - }) - } - - #[inline] - fn cbrt(&self) -> Self { - check_zero_or_one!(self); - - #[cfg(not(test))] - // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested - if let Some(n) = self.to_u128() { - return n.cbrt().into(); + let n = n as ExpType; + if bits <= n { + return Self::ONE; } - let bits = self.bits(); - let max_bits = bits / 3 + 1; + + let max_bits = bits / n + 1; let guess = Self::power_of_two(max_bits); + let n_minus_1 = n - 1; + guess.fixpoint(max_bits, |s| { - let q = self / (s * s); - let t: Self = (s << 1) + q; - t.div_rem_digit(3).0 + let q = self / s.pow(n_minus_1); + let mul: Self = n_minus_1.into(); + let t: Self = s * mul + q; + t.div_rem_unchecked(n.into()).0 }) } - - #[inline] - fn nth_root(&self, n: u32) -> Self { - match n { - 0 => panic!(crate::errors::err_msg!("attempt to calculate zeroth root")), - 1 => *self, - 2 => self.sqrt(), - 3 => self.cbrt(), - _ => { - check_zero_or_one!(self); - - #[cfg(not(test))] - // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested - if let Some(x) = self.to_u128() { - return x.nth_root(n).into(); - } - let bits = self.bits(); - let n = n as ExpType; - if bits <= n { - return Self::ONE; - } - - let max_bits = bits / n + 1; - - let guess = Self::power_of_two(max_bits); - let n_minus_1 = n - 1; - - guess.fixpoint(max_bits, |s| { - let q = self / s.pow(n_minus_1); - let mul: Self = n_minus_1.into(); - let t: Self = s * mul + q; - t.div_rem_unchecked(n.into()).0 - }) - } - } - } - } - - impl ToPrimitive for $BUint { - to_int! { - $Digit; - to_u8 -> u8, - to_u16 -> u16, - to_u32 -> u32, - to_u64 -> u64, - to_u128 -> u128, - to_usize -> usize, - - 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_()) - } } + } +} - impl Unsigned for $BUint {} - }; +impl ToPrimitive for BUintD8 { + to_int! { + to_u8 -> u8, + to_u16 -> u16, + to_u32 -> u32, + to_u64 -> u64, + to_u128 -> u128, + to_usize -> usize, + + 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_()) + } } +impl Unsigned for BUintD8 {} + #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::types::utest; - +mod tests { + use crate::test::types::*; + crate::int::numtraits::tests!(utest); } - -crate::macro_impl!(numtraits); diff --git a/src/buint/ops.rs b/src/buint/ops.rs index 649a31a..f5f4751 100644 --- a/src/buint/ops.rs +++ b/src/buint/ops.rs @@ -1,138 +1,133 @@ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit, BIntD8}; use crate::ExpType; use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, }; -macro_rules! ops { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl Add<$Digit> for $BUint { - type Output = Self; - - #[inline] - fn add(self, rhs: $Digit) -> Self { - let mut out = self; - let result = digit::$Digit::carrying_add(out.digits[0], rhs, false); - out.digits[0] = result.0; - let mut carry = result.1; - let mut i = 1; - while i < N && carry { - let result = out.digits[i].overflowing_add(1); - out.digits[i] = result.0; - carry = result.1; - i += 1; - } - out - } +impl Add for BUintD8 { + type Output = Self; + + #[inline] + fn add(self, rhs: Digit) -> Self { + let mut out = self; + let result = digit::carrying_add(out.digits[0], rhs, false); + out.digits[0] = result.0; + let mut carry = result.1; + let mut i = 1; + while i < N && carry { + let result = out.digits[i].overflowing_add(1); + out.digits[i] = result.0; + carry = result.1; + i += 1; } + out + } +} - impl BitAnd for $BUint { - type Output = Self; +impl BitAnd for BUintD8 { + type Output = Self; - #[inline] - fn bitand(self, rhs: Self) -> Self { - Self::bitand(self, rhs) - } - } + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self::bitand(self, rhs) + } +} - impl BitOr for $BUint { - type Output = Self; +impl BitOr for BUintD8 { + type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self { - Self::bitor(self, rhs) - } - } + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self::bitor(self, rhs) + } +} - impl BitXor for $BUint { - type Output = Self; +impl BitXor for BUintD8 { + type Output = Self; - #[inline] - fn bitxor(self, rhs: Self) -> Self { - Self::bitxor(self, rhs) - } - } + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self::bitxor(self, rhs) + } +} - impl Div for $BUint { - type Output = Self; +impl Div for BUintD8 { + type Output = Self; - #[inline] - fn div(self, rhs: Self) -> Self { - Self::div(self, rhs) - } - } + #[inline] + fn div(self, rhs: Self) -> Self { + Self::div(self, rhs) + } +} - impl Div<$Digit> for $BUint { - type Output = Self; +impl Div for BUintD8 { + type Output = Self; - #[inline] - fn div(self, rhs: $Digit) -> Self { - self.div_rem_digit(rhs).0 - } - } + #[inline] + fn div(self, rhs: Digit) -> Self { + self.div_rem_digit(rhs).0 + } +} - impl Not for $BUint { - type Output = Self; +impl Not for BUintD8 { + type Output = Self; - #[inline] - fn not(self) -> Self { - Self::not(self) - } - } + #[inline] + fn not(self) -> Self { + Self::not(self) + } +} - impl Rem for $BUint { - type Output = Self; +impl Rem for BUintD8 { + type Output = Self; - #[inline] - fn rem(self, rhs: Self) -> Self { - Self::rem(self, rhs) - } - } + #[inline] + fn rem(self, rhs: Self) -> Self { + Self::rem(self, rhs) + } +} - impl Rem<$Digit> for $BUint { - type Output = $Digit; +impl Rem for BUintD8 { + type Output = Digit; - #[inline] - fn rem(self, rhs: $Digit) -> $Digit { - self.div_rem_digit(rhs).1 - } - } + #[inline] + fn rem(self, rhs: Digit) -> Digit { + self.div_rem_digit(rhs).1 + } +} - crate::int::ops::impls!($BUint, $BUint, $BInt); - - #[cfg(all(test, test_int_bits = "64"))] - paste::paste! { - mod [<$Digit _add_digit_test>] { - use super::*; - use crate::test::{test_bignum, types::utest}; - use crate::test::types::big_types::$Digit::*; - - quickcheck::quickcheck! { - fn add_digit(a: utest, b: $Digit) -> quickcheck::TestResult { - use crate::cast::As; - - let c: utest = b.as_(); - match a.checked_add(c) { - None => quickcheck::TestResult::discard(), - Some(_d) => { - let e: UTEST = b.as_(); - let f: UTEST = a.as_(); - quickcheck::TestResult::from_bool(f + e == f + b) - } - } - } +crate::int::ops::impls!(BUintD8); + +#[cfg(all(test, test_int_bits = "64"))] +paste::paste! { + mod [] { + use super::*; + use crate::test::{test_bignum, types::utest}; + use crate::test::types::big_types::Digit::*; + + quickcheck::quickcheck! { + fn add_digit(a: utest, b: Digit) -> quickcheck::TestResult { + use crate::cast::As; + + let c: utest = b.as_(); + match a.checked_add(c) { + None => quickcheck::TestResult::discard(), + Some(_d) => { + let e: UTEST = b.as_(); + let f: UTEST = a.as_(); + quickcheck::TestResult::from_bool(f + e == f + b) + } } } } - }; + } } #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::{test_bignum, types::utest}; +mod tests { + use crate::test::{test_bignum, types::*}; crate::int::ops::tests!(utest); } - -crate::macro_impl!(ops); diff --git a/src/buint/overflowing.rs b/src/buint/overflowing.rs index b346821..16e908b 100644 --- a/src/buint/overflowing.rs +++ b/src/buint/overflowing.rs @@ -1,159 +1,155 @@ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit, BIntD8}; use crate::doc; use crate::ExpType; -macro_rules! overflowing { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::overflowing::impl_desc!()] - impl $BUint { - #[doc = doc::overflowing::overflowing_add!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let mut out = Self::ZERO; - let mut carry = false; - let mut i = 0; - while i < N { - let result = digit::$Digit::carrying_add(self.digits[i], rhs.digits[i], carry); - out.digits[i] = result.0; - carry = result.1; - i += 1; - } - (out, carry) - } +#[doc = doc::overflowing::impl_desc!()] +impl BUintD8 { + #[doc = doc::overflowing::overflowing_add!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let mut out = Self::ZERO; + let mut carry = false; + let mut i = 0; + while i < N { + let result = digit::carrying_add(self.digits[i], rhs.digits[i], carry); + out.digits[i] = result.0; + carry = result.1; + i += 1; + } + (out, carry) + } - #[doc = doc::overflowing::overflowing_add_signed!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_add_signed(self, rhs: $BInt) -> (Self, bool) { - let (sum, overflow) = self.overflowing_add(rhs.to_bits()); - (sum, rhs.is_negative() != overflow) - } + #[doc = doc::overflowing::overflowing_add_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_add_signed(self, rhs: BIntD8) -> (Self, bool) { + let (sum, overflow) = self.overflowing_add(rhs.to_bits()); + (sum, rhs.is_negative() != overflow) + } - #[doc = doc::overflowing::overflowing_sub!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let mut out = Self::ZERO; - let mut borrow = false; - let mut i = 0; - while i < N { - let result = - digit::$Digit::borrowing_sub(self.digits[i], rhs.digits[i], borrow); - out.digits[i] = result.0; - borrow = result.1; - i += 1; - } - (out, borrow) - } + #[doc = doc::overflowing::overflowing_sub!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let mut out = Self::ZERO; + let mut borrow = false; + let mut i = 0; + while i < N { + let result = digit::borrowing_sub(self.digits[i], rhs.digits[i], borrow); + out.digits[i] = result.0; + borrow = result.1; + i += 1; + } + (out, borrow) + } - #[doc = doc::overflowing::overflowing_mul!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - // TODO: implement a faster multiplication algorithm for large values of `N` - self.long_mul(rhs) - } + #[doc = doc::overflowing::overflowing_mul!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + // TODO: implement a faster multiplication algorithm for large values of `N` + self.long_mul(rhs) + } - #[doc = doc::overflowing::overflowing_div!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - (self.wrapping_div(rhs), false) - } + #[doc = doc::overflowing::overflowing_div!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + (self.wrapping_div(rhs), false) + } - #[doc = doc::overflowing::overflowing_div_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - self.overflowing_div(rhs) - } + #[doc = doc::overflowing::overflowing_div_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + self.overflowing_div(rhs) + } - #[doc = doc::overflowing::overflowing_rem!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - (self.wrapping_rem(rhs), false) - } + #[doc = doc::overflowing::overflowing_rem!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + (self.wrapping_rem(rhs), false) + } - #[doc = doc::overflowing::overflowing_rem_euclid!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - self.overflowing_rem(rhs) - } + #[doc = doc::overflowing::overflowing_rem_euclid!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + 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) - } + #[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_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) } + } + } - #[doc = doc::overflowing::overflowing_pow!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn overflowing_pow(mut self, mut pow: ExpType) -> (Self, bool) { - // exponentiation by squaring - if pow == 0 { - return (Self::ONE, false); - } - let mut overflow = false; - let mut y = Self::ONE; - while pow > 1 { - if pow & 1 == 1 { - let (prod, o) = y.overflowing_mul(self); - overflow |= o; - y = prod; - } - let (prod, o) = self.overflowing_mul(self); - overflow |= o; - self = prod; - pow >>= 1; - } - let (prod, o) = self.overflowing_mul(y); - (prod, o || overflow) + #[doc = doc::overflowing::overflowing_pow!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn overflowing_pow(mut self, mut pow: ExpType) -> (Self, bool) { + // exponentiation by squaring + if pow == 0 { + return (Self::ONE, false); + } + let mut overflow = false; + let mut y = Self::ONE; + while pow > 1 { + if pow & 1 == 1 { + let (prod, o) = y.overflowing_mul(self); + overflow |= o; + y = prod; } + let (prod, o) = self.overflowing_mul(self); + overflow |= o; + self = prod; + pow >>= 1; } - }; + let (prod, o) = self.overflowing_mul(y); + (prod, o || overflow) + } } #[cfg(test)] -crate::test::all_digit_tests! { - use crate::test::{test_bignum, types::utest}; +mod tests { + use crate::test::{test_bignum, types::*}; test_bignum! { function: ::overflowing_add(a: utest, b: utest) @@ -193,5 +189,3 @@ crate::test::all_digit_tests! { function: ::overflowing_pow(a: utest, b: u16) } } - -crate::macro_impl!(overflowing); diff --git a/src/buint/radix.rs b/src/buint/radix.rs index 797d1b4..33f32f8 100644 --- a/src/buint/radix.rs +++ b/src/buint/radix.rs @@ -7,7 +7,8 @@ Copyright (c) 2014 The Rust Project Developers The original license file and copyright notice for `num_bigint` can be found in this project's root at licenses/LICENSE-num-bigint. */ -use crate::digit; +use super::BUintD8; +use crate::{digit, Digit}; use crate::doc; use crate::errors::ParseIntError; use crate::int::radix::assert_range; @@ -32,581 +33,564 @@ const fn div_ceil(a: ExpType, b: ExpType) -> ExpType { } } -macro_rules! radix { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::radix::impl_desc!($BUint)] - impl $BUint { - #[inline] - const fn radix_base(radix: u32) -> ($Digit, usize) { - let mut power: usize = 1; - let radix = radix as $Digit; - let mut base = radix; - loop { - match base.checked_mul(radix) { - Some(n) => { - base = n; - power += 1; - } - None => return (base, power), - } +#[doc = doc::radix::impl_desc!(BUintD8)] +impl BUintD8 { + #[inline] + const fn radix_base(radix: u32) -> (Digit, usize) { + let mut power: usize = 1; + let radix = radix as Digit; + let mut base = radix; + loop { + match base.checked_mul(radix) { + Some(n) => { + base = n; + power += 1; } + None => return (base, power), } + } + } - #[inline] - const fn radix_base_half(radix: u32) -> ($Digit, usize) { - const HALF_BITS_MAX: $Digit = $Digit::MAX >> ($Digit::BITS / 2); - - let mut power: usize = 1; - let radix = radix as $Digit; - let mut base = radix; - loop { - match base.checked_mul(radix) { - Some(n) if n <= HALF_BITS_MAX => { - base = n; - power += 1; - } - _ => return (base, power), - } + #[inline] + const fn radix_base_half(radix: u32) -> (Digit, usize) { + const HALF_BITS_MAX: Digit = Digit::MAX >> (Digit::BITS / 2); + + let mut power: usize = 1; + let radix = radix as Digit; + let mut base = radix; + loop { + match base.checked_mul(radix) { + Some(n) if n <= HALF_BITS_MAX => { + base = n; + power += 1; } + _ => return (base, power), } + } + } - /// Converts a byte slice in a given base to an integer. The input slice must contain ascii/utf8 characters in [0-9a-zA-Z]. - /// - /// This function is equivalent to the [`from_str_radix`](#method.from_str_radix) function for a string slice equivalent to the byte slice and the same radix. - /// - /// Returns `None` if the conversion of the byte slice to string slice fails or if a digit is larger than or equal to the given radix, otherwise the integer is wrapped in `Some`. - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36 inclusive. - /// - /// # Examples - /// - /// ``` - /// use bnum::types::U512; - /// - /// let src = "394857hdgfjhsnkg947dgfjkeita"; - /// assert_eq!(U512::from_str_radix(src, 32).ok(), U512::parse_bytes(src.as_bytes(), 32)); - /// ``` - #[inline] - pub const fn parse_bytes(buf: &[u8], radix: u32) -> Option { - let s = crate::nightly::option_try!(crate::nightly::ok!(core::str::from_utf8(buf))); - crate::nightly::ok!(Self::from_str_radix(s, radix)) - } + /// Converts a byte slice in a given base to an integer. The input slice must contain ascii/utf8 characters in [0-9a-zA-Z]. + /// + /// This function is equivalent to the [`from_str_radix`](#method.from_str_radix) function for a string slice equivalent to the byte slice and the same radix. + /// + /// Returns `None` if the conversion of the byte slice to string slice fails or if a digit is larger than or equal to the given radix, otherwise the integer is wrapped in `Some`. + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36 inclusive. + /// + /// # Examples + /// + /// ``` + /// use bnum::types::U512; + /// + /// let src = "394857hdgfjhsnkg947dgfjkeita"; + /// assert_eq!(U512::from_str_radix(src, 32).ok(), U512::parse_bytes(src.as_bytes(), 32)); + /// ``` + #[inline] + pub const fn parse_bytes(buf: &[u8], radix: u32) -> Option { + let s = crate::nightly::option_try!(crate::nightly::ok!(core::str::from_utf8(buf))); + crate::nightly::ok!(Self::from_str_radix(s, radix)) + } - /// 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); - } + /// 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)) - } + 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); - } + /// 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)) - } + 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 - } + #[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 + } + } - /// Converts a string slice in a given base to an integer. - /// - /// The string is expected to be an optional `+` sign followed by digits. Leading and trailing whitespace represent an error. Digits are a subset of these characters, depending on `radix`: - /// - /// - `0-9` - /// - `a-z` - /// - `A-Z` - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36 inclusive. - /// - /// # Examples - /// - /// ``` - /// use bnum::types::U512; - /// - /// 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() { - 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) - } + /// Converts a string slice in a given base to an integer. + /// + /// The string is expected to be an optional `+` sign followed by digits. Leading and trailing whitespace represent an error. Digits are a subset of these characters, depending on `radix`: + /// + /// - `0-9` + /// - `a-z` + /// - `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36 inclusive. + /// + /// # Examples + /// + /// ``` + /// use bnum::types::U512; + /// + /// 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() { + 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()), - } - } + #[doc = doc::radix::parse_str_radix!(BUintD8)] + #[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; - let radix_u8 = radix as u8; - - if full_digits > N || full_digits == N && remaining_digits != 0 { - let mut i = if leading_sign { 1 } else { 0 }; - while i < N * base_digits_per_digit + if leading_sign { 1 } else { 0 } { - if Self::byte_to_digit::(buf[i]) >= radix_u8 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - i += 1; - } + 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::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; + let radix_u8 = radix as u8; + + if full_digits > N || full_digits == N && remaining_digits != 0 { + let mut i = if leading_sign { 1 } else { 0 }; + while i < N * base_digits_per_digit + if leading_sign { 1 } else { 0 } { + if Self::byte_to_digit::(buf[i]) >= radix_u8 { return Err(ParseIntError { - kind: IntErrorKind::PosOverflow, + kind: IntErrorKind::InvalidDigit, }); } + i += 1; + } + return Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }); + } - 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*/ 0 => { // TODO: for now, we don't use this, as hard to get the errors right - 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 { - // panic!("noooooo"); - 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 + 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 { - 0 + i * base_digits_per_digit + j }; - 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; + let d = Self::byte_to_digit::(buf[idx]); + if d >= radix_u8 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); } - 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; - } + 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*/ + 0 => { + // TODO: for now, we don't use this, as hard to get the errors right + 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 { + // panic!("noooooo"); + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + out.digits[index] |= (d as Digit) << shift; + shift += log2r; + if shift >= digit::BITS_U8 { + shift -= digit::BITS_U8; + let carry = (d as Digit) >> (log2r - shift); + index += 1; + if index == N { if carry != 0 { - while start < buf.len() && start < end { // TODO: this isn't quite correct behaviour - let idx = if BE { - start - } else { - buf.len() - 1 - start - }; - let d = Self::byte_to_digit::(buf[idx]); - if d >= radix_u8 { - return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, - }); - } - start += 1; - } 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 - }; + 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 { + if d != 0 { return Err(ParseIntError { - kind: IntErrorKind::InvalidDigit, + kind: IntErrorKind::PosOverflow, }); } - 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; + return Ok(out); + } else { + out.digits[index] = carry; } - Ok(out) } } + 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::carrying_mul(out.digits[j], base, carry, 0); + carry = high; + out.digits[j] = low; + j += 1; + } + if carry != 0 { + while start < buf.len() && start < end { + // TODO: this isn't quite correct behaviour + let idx = if BE { start } else { buf.len() - 1 - start }; + let d = Self::byte_to_digit::(buf[idx]); + if d >= radix_u8 { + return Err(ParseIntError { + kind: IntErrorKind::InvalidDigit, + }); + } + start += 1; + } + return Err(ParseIntError { + kind: IntErrorKind::PosOverflow, + }); + } - /// Returns the integer as a string in the given radix. - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36 inclusive. - /// - /// # Examples - /// - /// ``` - /// use bnum::types::U512; - /// - /// let src = "934857djkfghhkdfgbf9345hdfkh"; - /// let n = U512::from_str_radix(src, 36).unwrap(); - /// assert_eq!(n.to_str_radix(36), src); - /// ``` - #[inline] - pub fn to_str_radix(&self, radix: u32) -> String { - let mut out = Self::to_radix_be(self, radix); - - for byte in out.iter_mut() { - if *byte < 10 { - *byte += b'0'; - } else { - *byte += b'a' - 10; + 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; } - unsafe { String::from_utf8_unchecked(out) } + Ok(out) } + } + } - /// Returns the integer in the given base in big-endian digit order. - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 256 inclusive. - /// - /// ``` - /// use bnum::types::U512; - /// - /// let digits = &[3, 55, 60, 100, 5, 0, 5, 88]; - /// let n = U512::from_radix_be(digits, 120).unwrap(); - /// assert_eq!(n.to_radix_be(120), digits); - /// ``` - #[inline] - pub fn to_radix_be(&self, radix: u32) -> Vec { - let mut v = self.to_radix_le(radix); - v.reverse(); - v + /// Returns the integer as a string in the given radix. + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36 inclusive. + /// + /// # Examples + /// + /// ``` + /// use bnum::types::U512; + /// + /// let src = "934857djkfghhkdfgbf9345hdfkh"; + /// let n = U512::from_str_radix(src, 36).unwrap(); + /// assert_eq!(n.to_str_radix(36), src); + /// ``` + #[inline] + pub fn to_str_radix(&self, radix: u32) -> String { + let mut out = Self::to_radix_be(self, radix); + + for byte in out.iter_mut() { + if *byte < 10 { + *byte += b'0'; + } else { + *byte += b'a' - 10; } + } + unsafe { String::from_utf8_unchecked(out) } + } - /// Returns the integer in the given base in little-endian digit order. - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 256 inclusive. - /// - /// ``` - /// use bnum::types::U512; - /// - /// let digits = &[1, 67, 88, 200, 55, 68, 87, 120, 178]; - /// let n = U512::from_radix_le(digits, 250).unwrap(); - /// assert_eq!(n.to_radix_le(250), digits); - /// ``` - pub fn to_radix_le(&self, radix: u32) -> Vec { - if self.is_zero() { - vec![0] - } else if radix.is_power_of_two() { - if $Digit::BITS == 8 && radix == 256 { - return (&self.digits[0..=self.last_digit_index()]) - .into_iter() - .map(|d| *d as u8) - .collect(); // we can cast to `u8` here as the underlying digit must be a `u8` anyway - } + /// Returns the integer in the given base in big-endian digit order. + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 256 inclusive. + /// + /// ``` + /// use bnum::types::U512; + /// + /// let digits = &[3, 55, 60, 100, 5, 0, 5, 88]; + /// let n = U512::from_radix_be(digits, 120).unwrap(); + /// assert_eq!(n.to_radix_be(120), digits); + /// ``` + #[inline] + pub fn to_radix_be(&self, radix: u32) -> Vec { + let mut v = self.to_radix_le(radix); + v.reverse(); + v + } - let bits = ilog2(radix); - if digit::$Digit::BITS_U8 % bits == 0 { - self.to_bitwise_digits_le(bits) - } else { - self.to_inexact_bitwise_digits_le(bits) - } - } else if radix == 10 { - self.to_radix_digits_le(10) - } else { - self.to_radix_digits_le(radix) - } + /// Returns the integer in the given base in little-endian digit order. + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 256 inclusive. + /// + /// ``` + /// use bnum::types::U512; + /// + /// let digits = &[1, 67, 88, 200, 55, 68, 87, 120, 178]; + /// let n = U512::from_radix_le(digits, 250).unwrap(); + /// assert_eq!(n.to_radix_le(250), digits); + /// ``` + pub fn to_radix_le(&self, radix: u32) -> Vec { + if self.is_zero() { + vec![0] + } else if radix.is_power_of_two() { + if Digit::BITS == 8 && radix == 256 { + return (&self.digits[0..=self.last_digit_index()]) + .into_iter() + .map(|d| *d as u8) + .collect(); // we can cast to `u8` here as the underlying digit must be a `u8` anyway } - fn to_bitwise_digits_le(self, bits: u8) -> Vec { - let last_digit_index = self.last_digit_index(); - let mask: $Digit = (1 << bits) - 1; - let digits_per_big_digit = digit::$Digit::BITS_U8 / bits; - let digits = div_ceil(self.bits(), bits as ExpType); - let mut out = Vec::with_capacity(digits as usize); + let bits = ilog2(radix); + if digit::BITS_U8 % bits == 0 { + self.to_bitwise_digits_le(bits) + } else { + self.to_inexact_bitwise_digits_le(bits) + } + } else if radix == 10 { + self.to_radix_digits_le(10) + } else { + self.to_radix_digits_le(radix) + } + } - let mut r = self.digits[last_digit_index]; + fn to_bitwise_digits_le(self, bits: u8) -> Vec { + let last_digit_index = self.last_digit_index(); + let mask: Digit = (1 << bits) - 1; + let digits_per_big_digit = digit::BITS_U8 / bits; + let digits = div_ceil(self.bits(), bits as ExpType); + let mut out = Vec::with_capacity(digits as usize); - for mut d in IntoIterator::into_iter(self.digits).take(last_digit_index) { - for _ in 0..digits_per_big_digit { - out.push((d & mask) as u8); - d >>= bits; - } - } - while r != 0 { - out.push((r & mask) as u8); - r >>= bits; - } - out - } + let mut r = self.digits[last_digit_index]; - fn to_inexact_bitwise_digits_le(self, bits: u8) -> Vec { - let mask: $Digit = (1 << bits) - 1; - let digits = div_ceil(self.bits(), bits as ExpType); - let mut out = Vec::with_capacity(digits as usize); - let mut r = 0; - let mut rbits = 0; - for c in self.digits { - r |= c << rbits; - rbits += digit::$Digit::BITS_U8; - - while rbits >= bits { - out.push((r & mask) as u8); - r >>= bits; - - if rbits > digit::$Digit::BITS_U8 { - r = c >> (digit::$Digit::BITS_U8 - (rbits - bits)); - } - rbits -= bits; - } - } - if rbits != 0 { - out.push(r as u8); - } - while let Some(&0) = out.last() { - out.pop(); - } - out + for mut d in IntoIterator::into_iter(self.digits).take(last_digit_index) { + for _ in 0..digits_per_big_digit { + out.push((d & mask) as u8); + d >>= bits; } + } + while r != 0 { + out.push((r & mask) as u8); + r >>= bits; + } + out + } - fn to_radix_digits_le(self, radix: u32) -> Vec { - let radix_digits = div_ceil(self.bits(), ilog2(radix) as ExpType); - let mut out = Vec::with_capacity(radix_digits as usize); - let (base, power) = Self::radix_base_half(radix); - let radix = radix as $Digit; - let mut copy = self; - while copy.last_digit_index() > 0 { - let (q, mut r) = copy.div_rem_digit(base); - for _ in 0..power { - out.push((r % radix) as u8); - r /= radix; - } - copy = q; - } - let mut r = copy.digits[0]; - while r != 0 { - out.push((r % radix) as u8); - r /= radix; + fn to_inexact_bitwise_digits_le(self, bits: u8) -> Vec { + let mask: Digit = (1 << bits) - 1; + let digits = div_ceil(self.bits(), bits as ExpType); + let mut out = Vec::with_capacity(digits as usize); + let mut r = 0; + let mut rbits = 0; + for c in self.digits { + r |= c << rbits; + rbits += digit::BITS_U8; + + while rbits >= bits { + out.push((r & mask) as u8); + r >>= bits; + + if rbits > digit::BITS_U8 { + r = c >> (digit::BITS_U8 - (rbits - bits)); } - out + rbits -= bits; } } + if rbits != 0 { + out.push(r as u8); + } + while let Some(&0) = out.last() { + out.pop(); + } + out + } - impl FromStr for $BUint { - type Err = ParseIntError; - - fn from_str(src: &str) -> Result { - Self::from_str_radix(src, 10) + fn to_radix_digits_le(self, radix: u32) -> Vec { + let radix_digits = div_ceil(self.bits(), ilog2(radix) as ExpType); + let mut out = Vec::with_capacity(radix_digits as usize); + let (base, power) = Self::radix_base_half(radix); + let radix = radix as Digit; + let mut copy = self; + while copy.last_digit_index() > 0 { + let (q, mut r) = copy.div_rem_digit(base); + for _ in 0..power { + out.push((r % radix) as u8); + r /= radix; } + copy = q; + } + let mut r = copy.digits[0]; + while r != 0 { + out.push((r % radix) as u8); + r /= radix; } - }; + out + } +} + +impl FromStr for BUintD8 { + type Err = ParseIntError; + + fn from_str(src: &str) -> Result { + Self::from_str_radix(src, 10) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::{quickcheck_from_to_radix, test_bignum, self}; - use crate::BUint; use core::str::FromStr; - use crate::test::types::utest; + use crate::test::types::*; + use crate::BUintD8; test_bignum! { @@ -679,15 +663,13 @@ crate::test::all_digit_tests! { #[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(); + let u = BUintD8::<100>::parse_bytes(src.as_bytes(), 35).unwrap(); + let v = BUintD8::<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); + let option = BUintD8::<100>::parse_bytes(bytes, 20); assert!(option.is_none()); } } - -crate::macro_impl!(radix); diff --git a/src/buint/saturating.rs b/src/buint/saturating.rs index fc5adba..c9e7cc1 100644 --- a/src/buint/saturating.rs +++ b/src/buint/saturating.rs @@ -1,79 +1,77 @@ +use super::BUintD8; +use crate::{digit, Digit, BIntD8}; use crate::doc; use crate::ExpType; -macro_rules! saturating { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::saturating::impl_desc!()] - impl $BUint { - #[inline] - const fn saturate_up((int, overflow): ($BUint, bool)) -> $BUint { - if overflow { - $BUint::MAX - } else { - int - } - } +#[doc = doc::saturating::impl_desc!()] +impl BUintD8 { + #[inline] + const fn saturate_up((int, overflow): (BUintD8, bool)) -> BUintD8 { + if overflow { + BUintD8::MAX + } else { + int + } + } - #[inline] - const fn saturate_down((int, overflow): ($BUint, bool)) -> $BUint { - if overflow { - $BUint::MIN - } else { - int - } - } + #[inline] + const fn saturate_down((int, overflow): (BUintD8, bool)) -> BUintD8 { + if overflow { + BUintD8::MIN + } else { + int + } + } - #[doc = doc::saturating::saturating_add!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - Self::saturate_up(self.overflowing_add(rhs)) - } + #[doc = doc::saturating::saturating_add!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + Self::saturate_up(self.overflowing_add(rhs)) + } - #[doc = doc::saturating::saturating_add_signed!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_add_signed(self, rhs: $BInt) -> Self { - if rhs.is_negative() { - Self::saturate_down(self.overflowing_add_signed(rhs)) - } else { - Self::saturate_up(self.overflowing_add_signed(rhs)) - } - } + #[doc = doc::saturating::saturating_add_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_add_signed(self, rhs: BIntD8) -> Self { + if rhs.is_negative() { + Self::saturate_down(self.overflowing_add_signed(rhs)) + } else { + Self::saturate_up(self.overflowing_add_signed(rhs)) + } + } - #[doc = doc::saturating::saturating_sub!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - Self::saturate_down(self.overflowing_sub(rhs)) - } + #[doc = doc::saturating::saturating_sub!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + Self::saturate_down(self.overflowing_sub(rhs)) + } - #[doc = doc::saturating::saturating_mul!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_mul(self, rhs: Self) -> Self { - Self::saturate_up(self.overflowing_mul(rhs)) - } + #[doc = doc::saturating::saturating_mul!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_mul(self, rhs: Self) -> Self { + Self::saturate_up(self.overflowing_mul(rhs)) + } - #[doc = doc::saturating::saturating_div!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_div(self, rhs: Self) -> Self { - self.div_euclid(rhs) - } + #[doc = doc::saturating::saturating_div!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_div(self, rhs: Self) -> Self { + self.div_euclid(rhs) + } - #[doc = doc::saturating::saturating_pow!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn saturating_pow(self, exp: ExpType) -> Self { - Self::saturate_up(self.overflowing_pow(exp)) - } - } - }; + #[doc = doc::saturating::saturating_pow!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn saturating_pow(self, exp: ExpType) -> Self { + Self::saturate_up(self.overflowing_pow(exp)) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::test_bignum; use crate::test::types::*; @@ -97,5 +95,3 @@ crate::test::all_digit_tests! { function: ::saturating_pow(a: utest, b: u16) } } - -crate::macro_impl!(saturating); diff --git a/src/buint/strict.rs b/src/buint/strict.rs index 972935d..e575676 100644 --- a/src/buint/strict.rs +++ b/src/buint/strict.rs @@ -1,24 +1,23 @@ -macro_rules! strict { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - #[doc = doc::strict::impl_desc!()] - impl $BUint { - crate::int::strict::impls!(U); +use super::BUintD8; +use crate::{digit, Digit, BIntD8}; - #[doc = doc::strict::strict_add_signed!(U)] - #[must_use = doc::must_use_op!()] - #[inline] - pub const fn strict_add_signed(self, rhs: $BInt) -> Self { - crate::errors::option_expect!( - self.checked_add_signed(rhs), - crate::errors::err_msg!("attempt to add with overflow") - ) - } - } - }; +#[doc = doc::strict::impl_desc!()] +impl BUintD8 { + crate::int::strict::impls!(U); + + #[doc = doc::strict::strict_add_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn strict_add_signed(self, rhs: BIntD8) -> Self { + crate::errors::option_expect!( + self.checked_add_signed(rhs), + crate::errors::err_msg!("attempt to add with overflow") + ) + } } #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { crate::int::strict::tests!(utest); test_bignum! { @@ -28,5 +27,3 @@ crate::test::all_digit_tests! { } use crate::doc; - -crate::macro_impl!(strict); diff --git a/src/buint/unchecked.rs b/src/buint/unchecked.rs index 1f2bfe7..8e5adb8 100644 --- a/src/buint/unchecked.rs +++ b/src/buint/unchecked.rs @@ -1,16 +1,13 @@ -macro_rules! unchecked { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - crate::int::unchecked::impls!($BUint, U); - }; -} +use super::BUintD8; +use crate::{digit, Digit}; + +crate::int::unchecked::impls!(BUintD8, U); #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::types::*; crate::int::unchecked::tests!(utest); } use crate::doc; - -crate::macro_impl!(unchecked); diff --git a/src/buint/wrapping.rs b/src/buint/wrapping.rs index 5077c3f..d8f107b 100644 --- a/src/buint/wrapping.rs +++ b/src/buint/wrapping.rs @@ -1,123 +1,127 @@ +use super::BUintD8; +use crate::{digit, Digit, BIntD8}; use crate::errors::option_expect; 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::impl_desc!()] +impl BUintD8 { + #[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_add_signed!(U)] + #[must_use = doc::must_use_op!()] + #[inline] + pub const fn wrapping_add_signed(self, rhs: BIntD8) -> 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_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 - } + #[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 + } - #[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!(errors::div_by_zero_message!())) - } + #[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!(errors::div_by_zero_message!()) + ) + } - #[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_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!(errors::rem_by_zero_message!())) - } + #[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!(errors::rem_by_zero_message!()) + ) + } - #[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_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_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_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_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_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, - } - } + #[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)] -crate::test::all_digit_tests! { - use crate::test::{test_bignum, types::{utest, itest}}; +mod tests { + use crate::test::{test_bignum, types::*}; #[test] #[should_panic(expected = "attempt to divide by zero")] @@ -182,5 +186,3 @@ crate::test::all_digit_tests! { ] } } - -crate::macro_impl!(wrapping); diff --git a/src/cast/float/float_from_uint.rs b/src/cast/float/float_from_uint.rs index 51e6575..bdb673b 100644 --- a/src/cast/float/float_from_uint.rs +++ b/src/cast/float/float_from_uint.rs @@ -1,8 +1,8 @@ -use crate::helpers::{Bits, One}; +use super::FloatCastHelper; use crate::cast::CastFrom; +use crate::helpers::{Bits, One}; use crate::ExpType; -use super::FloatCastHelper; -use core::ops::{Shr, Add}; +use core::ops::{Add, Shr}; pub trait CastFloatFromUintHelper: Bits + Shr { fn trailing_zeros(self) -> ExpType; @@ -28,10 +28,10 @@ where F: FloatCastHelper, F::SignedExp: TryFrom + One + Add, F::Mantissa: CastFrom + One, - U: CastFloatFromUintHelper + Copy + U: CastFloatFromUintHelper + Copy, { let bit_width = value.bits(); // number of bits needed to specify value = exponent of largest power of two smaller than value. so bit_width will be one less than the exponent of the float - // let mant = if F::M::BITS < U::BITS { + // let mant = if F::M::BITS < U::BITS { // } if bit_width == 0 { @@ -50,7 +50,7 @@ where // in this case, we can safely cast which preserves the value (no truncation) F::Mantissa::cast_from(value) << (F::MANTISSA_DIGITS - bit_width) } else { - // note: we know that exponent >= F::MANTISSA_DIGITS, so only way + // note: we know that exponent >= F::MANTISSA_DIGITS, so only way // TODO: we could generalise the round_mantissa_exponent code so that this could just be a call of round_mantissa_exponent instead let shift = bit_width - F::MANTISSA_DIGITS; let gte_half = value.bit(shift - 1); // is the discarded part greater than or equal to a half? @@ -67,7 +67,7 @@ where shifted_mantissa }; F::from_signed_parts(false, exponent, mantissa) - }, + } _ => F::INFINITY, // in this case, the exponent doesn't even fit into the float signed exponent, so is too big to be stored by F } -} \ No newline at end of file +} diff --git a/src/cast/float/mod.rs b/src/cast/float/mod.rs index ba01223..42b4f73 100644 --- a/src/cast/float/mod.rs +++ b/src/cast/float/mod.rs @@ -1,13 +1,21 @@ -use crate::ExpType; -use core::ops::{Add, Shl, Shr, BitAnd, Neg}; use crate::helpers::Bits; +use crate::ExpType; +use core::ops::{Add, BitAnd, Neg, Shl, Shr}; -mod uint_from_float; mod float_from_uint; -pub use uint_from_float::*; +mod uint_from_float; pub use float_from_uint::*; +pub use uint_from_float::*; -pub trait FloatMantissa: Sized + Shl + Shr + Add + BitAnd + PartialEq + Bits { +pub trait FloatMantissa: + Sized + + Shl + + Shr + + Add + + BitAnd + + PartialEq + + Bits +{ const ZERO: Self; const ONE: Self; const TWO: Self; @@ -60,11 +68,24 @@ pub trait ConvertFloatParts { fn into_normalised_signed_parts(self) -> (bool, Self::SignedExp, Self::Mantissa); fn from_raw_parts(sign: bool, exponent: Self::UnsignedExp, mantissa: Self::Mantissa) -> Self; - fn from_biased_parts(sign: bool, exponent: Self::UnsignedExp, mantissa: Self::Mantissa) -> Self; - fn from_signed_biased_parts(sign: bool, exponent: Self::SignedExp, mantissa: Self::Mantissa) -> Self; + fn from_biased_parts(sign: bool, exponent: Self::UnsignedExp, mantissa: Self::Mantissa) + -> Self; + fn from_signed_biased_parts( + sign: bool, + exponent: Self::SignedExp, + mantissa: Self::Mantissa, + ) -> Self; fn from_signed_parts(sign: bool, exponent: Self::SignedExp, mantissa: Self::Mantissa) -> Self; - fn round_exponent_mantissa(exponent: Self::SignedExp, mantissa: Self::Mantissa, shift: ExpType) -> (Self::SignedExp, Self::Mantissa); - fn from_normalised_signed_parts(sign: bool, exponent: Self::SignedExp, mantissa: Self::Mantissa) -> Self; + fn round_exponent_mantissa( + exponent: Self::SignedExp, + mantissa: Self::Mantissa, + shift: ExpType, + ) -> (Self::SignedExp, Self::Mantissa); + fn from_normalised_signed_parts( + sign: bool, + exponent: Self::SignedExp, + mantissa: Self::Mantissa, + ) -> Self; } macro_rules! impl_convert_float_parts_for_primitive_float { @@ -79,7 +100,9 @@ macro_rules! impl_convert_float_parts_for_primitive_float { let sign = self.is_sign_negative(); const SIGN_MASK: $mantissa_type = <$mantissa_type>::MAX >> 1; let exp = (self.to_bits() & SIGN_MASK) >> (<$float_type>::MANTISSA_DIGITS - 1); - let mant = self.to_bits() & (<$mantissa_type>::MAX >> (<$mantissa_type>::BITS - (<$float_type>::MANTISSA_DIGITS - 1))); + let mant = self.to_bits() + & (<$mantissa_type>::MAX + >> (<$mantissa_type>::BITS - (<$float_type>::MANTISSA_DIGITS - 1))); (sign, exp as _, mant) } @@ -90,7 +113,11 @@ macro_rules! impl_convert_float_parts_for_primitive_float { if exp == 0 { (sign, 1, mant) } else { - (sign, exp, mant | (1 << (<$float_type>::MANTISSA_DIGITS - 1))) + ( + sign, + exp, + mant | (1 << (<$float_type>::MANTISSA_DIGITS - 1)), + ) } } @@ -117,16 +144,21 @@ macro_rules! impl_convert_float_parts_for_primitive_float { } else { let normalised_mant = mant >> shift; let normalised_exp = exp - (shift as Self::SignedExp); - + (sign, normalised_exp, normalised_mant) } } #[inline] - fn from_raw_parts(sign: bool, exponent: Self::UnsignedExp, mantissa: Self::Mantissa) -> Self { + fn from_raw_parts( + sign: bool, + exponent: Self::UnsignedExp, + mantissa: Self::Mantissa, + ) -> Self { debug_assert!(mantissa.bits() <= <$float_type>::MANTISSA_DIGITS - 1); - let mut bits = (exponent as $mantissa_type) << (<$float_type>::MANTISSA_DIGITS - 1) | mantissa; + let mut bits = + (exponent as $mantissa_type) << (<$float_type>::MANTISSA_DIGITS - 1) | mantissa; if sign { bits |= 1 << ($float_bit_width - 1); } @@ -134,9 +166,13 @@ macro_rules! impl_convert_float_parts_for_primitive_float { } #[inline] - fn from_biased_parts(sign: bool, mut exponent: Self::UnsignedExp, mut mantissa: Self::Mantissa) -> Self { + fn from_biased_parts( + sign: bool, + mut exponent: Self::UnsignedExp, + mut mantissa: Self::Mantissa, + ) -> Self { debug_assert!(exponent != 0); - + if mantissa.bit(Self::MANTISSA_DIGITS - 1) { mantissa ^= 1 << (Self::MANTISSA_DIGITS - 1); } else { @@ -147,30 +183,47 @@ macro_rules! impl_convert_float_parts_for_primitive_float { } #[inline] - fn from_signed_biased_parts(sign: bool, exponent: Self::SignedExp, mantissa: Self::Mantissa) -> Self { + fn from_signed_biased_parts( + sign: bool, + exponent: Self::SignedExp, + mantissa: Self::Mantissa, + ) -> Self { debug_assert!(!exponent.is_negative()); let exponent = exponent as Self::UnsignedExp; Self::from_biased_parts(sign, exponent, mantissa) } #[inline] - fn from_signed_parts(sign: bool, exponent: Self::SignedExp, mantissa: Self::Mantissa) -> Self { - const EXP_BIAS: <$float_type as ConvertFloatParts>::SignedExp = <$float_type>::MAX_EXP - 1; + fn from_signed_parts( + sign: bool, + exponent: Self::SignedExp, + mantissa: Self::Mantissa, + ) -> Self { + const EXP_BIAS: <$float_type as ConvertFloatParts>::SignedExp = + <$float_type>::MAX_EXP - 1; let exponent = exponent + EXP_BIAS; Self::from_signed_biased_parts(sign, exponent, mantissa) } - + #[inline] - fn round_exponent_mantissa(mut exponent: Self::SignedExp, mantissa: Self::Mantissa, shift: ExpType) -> (Self::SignedExp, Self::Mantissa) { + fn round_exponent_mantissa( + mut exponent: Self::SignedExp, + mantissa: Self::Mantissa, + shift: ExpType, + ) -> (Self::SignedExp, Self::Mantissa) { let mut shifted_mantissa = mantissa >> shift; if !TIES_EVEN { return (exponent, shifted_mantissa); // if not TIES_EVEN, then we truncate } - let discarded_shifted_bits = mantissa & (<$mantissa_type>::MAX >> ($float_bit_width - shift)); - if discarded_shifted_bits.bit(shift - 1) { // in this case, the discarded portion is at least a half - if shifted_mantissa & 1 == 1 || !discarded_shifted_bits.is_power_of_two() { // in this case, ties to even says we round up. checking if not a power of two tells us that there is at least one bit set to 1 (after the most significant bit set to 1). we check in this order as is_odd is O(1) whereas is_power_of_two is O(N) + let discarded_shifted_bits = + mantissa & (<$mantissa_type>::MAX >> ($float_bit_width - shift)); + if discarded_shifted_bits.bit(shift - 1) { + // in this case, the discarded portion is at least a half + if shifted_mantissa & 1 == 1 || !discarded_shifted_bits.is_power_of_two() { + // in this case, ties to even says we round up. checking if not a power of two tells us that there is at least one bit set to 1 (after the most significant bit set to 1). we check in this order as is_odd is O(1) whereas is_power_of_two is O(N) shifted_mantissa = shifted_mantissa + 1; - if shifted_mantissa.bit(shift) { // check for overflow (with respect to the mantissa bit width) + if shifted_mantissa.bit(shift) { + // check for overflow (with respect to the mantissa bit width) exponent += 1; shifted_mantissa = shifted_mantissa >> 1; } @@ -180,13 +233,18 @@ macro_rules! impl_convert_float_parts_for_primitive_float { } #[inline] - fn from_normalised_signed_parts(sign: bool, exponent: Self::SignedExp, mantissa: Self::Mantissa) -> Self { + fn from_normalised_signed_parts( + sign: bool, + exponent: Self::SignedExp, + mantissa: Self::Mantissa, + ) -> Self { use crate::helpers::Bits; debug_assert!(mantissa == 0 || mantissa.bits() == Self::MANTISSA_DIGITS); if exponent < Self::MIN_EXP - 1 { let shift = (Self::MIN_EXP - 1 - exponent) as ExpType; - let (out_exponent, out_mantissa) = Self::round_exponent_mantissa::(Self::MIN_EXP - 1, mantissa, shift); + let (out_exponent, out_mantissa) = + Self::round_exponent_mantissa::(Self::MIN_EXP - 1, mantissa, shift); Self::from_signed_parts(sign, out_exponent, out_mantissa) } else { @@ -220,7 +278,8 @@ macro_rules! impl_cast_float_from_float_helper_for_primitive_float { const BITS: ExpType = $float_type_bit_width; const MANTISSA_DIGITS: ExpType = Self::MANTISSA_DIGITS as ExpType; const MAX_EXP: ::SignedExp = Self::MAX_EXP; - const MIN_SUBNORMAL_EXP: ::SignedExp = Self::MIN_EXP + 1 - Self::MANTISSA_DIGITS as ::SignedExp; + const MIN_SUBNORMAL_EXP: ::SignedExp = + Self::MIN_EXP + 1 - Self::MANTISSA_DIGITS as ::SignedExp; const INFINITY: Self = Self::INFINITY; const ZERO: Self = 0.0; const NEG_ZERO: Self = -0.0; @@ -235,7 +294,7 @@ macro_rules! impl_cast_float_from_float_helper_for_primitive_float { Self::is_infinite(*self) } } - } + }; } impl_cast_float_from_float_helper_for_primitive_float!(f32, u32, i32, 32); diff --git a/src/cast/float/uint_from_float.rs b/src/cast/float/uint_from_float.rs index 215907b..03fa852 100644 --- a/src/cast/float/uint_from_float.rs +++ b/src/cast/float/uint_from_float.rs @@ -1,9 +1,9 @@ -use core::ops::{Neg, Shl}; -use crate::cast::CastFrom; -use crate::ExpType; -use super::FloatMantissa; use super::FloatCastHelper; +use super::FloatMantissa; +use crate::cast::CastFrom; use crate::helpers::{Bits, One, Zero}; +use crate::ExpType; +use core::ops::{Neg, Shl}; pub trait CastUintFromFloatHelper: Zero + One + Bits { const MAX: Self; diff --git a/src/cast/mod.rs b/src/cast/mod.rs index 268d4ec..9a611d2 100644 --- a/src/cast/mod.rs +++ b/src/cast/mod.rs @@ -152,4 +152,4 @@ primitive_cast_impl!(char as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, primitive_cast_impl!(u8 as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, char]); multiple_impls!(u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); -pub(crate) mod float; \ No newline at end of file +pub(crate) mod float; diff --git a/src/digit.rs b/src/digit.rs index dc4a7d0..736f682 100644 --- a/src/digit.rs +++ b/src/digit.rs @@ -1,126 +1,115 @@ -macro_rules! digit_module { - ($Digit: ident, $SignedDigit: ty, $DoubleDigit: ty) => { - pub mod $Digit { - mod types { - pub type Digit = $Digit; - - pub type SignedDigit = $SignedDigit; - - pub type DoubleDigit = $DoubleDigit; - } - - use crate::ExpType; - - pub use types::*; - - pub const BITS: ExpType = $Digit::BITS as ExpType; - - pub const BITS_U8: u8 = BITS as u8; - - pub const BITS_MINUS_1: ExpType = BITS - 1; - - pub const BYTES: ExpType = BITS / 8; - - // This calculates log2 of BYTES as BYTES is guaranteed to only have one '1' bit, since it must be a power of two. - pub const BYTE_SHIFT: ExpType = BYTES.trailing_zeros() as ExpType; - - pub const BIT_SHIFT: ExpType = BITS.trailing_zeros() as ExpType; - - #[inline] - pub const fn to_double_digit(low: Digit, high: Digit) -> DoubleDigit { - ((high as DoubleDigit) << BITS) | low as DoubleDigit - } - - // TODO: these will no longer be necessary once const_bigint_helper_methods is stabilised: https://github.com/rust-lang/rust/issues/85532 - - #[inline] - pub const fn carrying_add(a: Digit, b: Digit, carry: bool) -> (Digit, bool) { - let (s1, o1) = a.overflowing_add(b); - if carry { - let (s2, o2) = s1.overflowing_add(1); - (s2, o1 || o2) - } else { - (s1, o1) - } - } - - #[inline] - pub const fn borrowing_sub(a: Digit, b: Digit, borrow: bool) -> (Digit, bool) { - let (s1, o1) = a.overflowing_sub(b); - if borrow { - let (s2, o2) = s1.overflowing_sub(1); - (s2, o1 || o2) - } else { - (s1, o1) - } - } - - #[inline] - pub const fn carrying_add_signed( - a: SignedDigit, - b: SignedDigit, - carry: bool, - ) -> (SignedDigit, bool) { - let (s1, o1) = a.overflowing_add(b); - if carry { - let (s2, o2) = s1.overflowing_add(1); - (s2, o1 != o2) - } else { - (s1, o1) - } - } - - #[inline] - pub const fn borrowing_sub_signed( - a: SignedDigit, - b: SignedDigit, - borrow: bool, - ) -> (SignedDigit, bool) { - let (s1, o1) = a.overflowing_sub(b); - if borrow { - let (s2, o2) = s1.overflowing_sub(1); - (s2, o1 != o2) - } else { - (s1, o1) - } - } - - #[inline] - pub const fn widening_mul(a: Digit, b: Digit) -> (Digit, Digit) { - let prod = a as DoubleDigit * b as DoubleDigit; - (prod as Digit, (prod >> BITS) as Digit) - } - - #[inline] - pub const fn carrying_mul( - a: Digit, - b: Digit, - carry: Digit, - current: Digit, - ) -> (Digit, Digit) { - let prod = carry as DoubleDigit - + current as DoubleDigit - + (a as DoubleDigit) * (b as DoubleDigit); - (prod as Digit, (prod >> BITS) as Digit) - } - - #[inline] - pub const fn div_rem_wide(low: Digit, high: Digit, rhs: Digit) -> (Digit, Digit) { - debug_assert!(high < rhs); - - let a = to_double_digit(low, high); - ( - (a / rhs as DoubleDigit) as Digit, - (a % rhs as DoubleDigit) as Digit, - ) - } - - pub const HEX_PADDING: usize = BITS as usize / 4; - } - }; +mod types { + pub type Digit = u8; + + pub type SignedDigit = i8; + + pub type DoubleDigit = i16; +} + +use crate::ExpType; + +pub use types::*; + +pub const BITS: ExpType = Digit::BITS as ExpType; + +pub const BITS_U8: u8 = BITS as u8; + +pub const BITS_MINUS_1: ExpType = BITS - 1; + +pub const BYTES: ExpType = BITS / 8; + +// This calculates log2 of BYTES as BYTES is guaranteed to only have one '1' bit, since it must be a power of two. +pub const BYTE_SHIFT: ExpType = BYTES.trailing_zeros() as ExpType; + +pub const BIT_SHIFT: ExpType = BITS.trailing_zeros() as ExpType; + +#[inline] +pub const fn to_double_digit(low: Digit, high: Digit) -> DoubleDigit { + ((high as DoubleDigit) << BITS) | low as DoubleDigit +} + +// TODO: these will no longer be necessary once const_bigint_helper_methods is stabilised: https://github.com/rust-lang/rust/issues/85532 + +#[inline] +pub const fn carrying_add(a: Digit, b: Digit, carry: bool) -> (Digit, bool) { + let (s1, o1) = a.overflowing_add(b); + if carry { + let (s2, o2) = s1.overflowing_add(1); + (s2, o1 || o2) + } else { + (s1, o1) + } +} + +#[inline] +pub const fn borrowing_sub(a: Digit, b: Digit, borrow: bool) -> (Digit, bool) { + let (s1, o1) = a.overflowing_sub(b); + if borrow { + let (s2, o2) = s1.overflowing_sub(1); + (s2, o1 || o2) + } else { + (s1, o1) + } +} + +#[inline] +pub const fn carrying_add_signed( + a: SignedDigit, + b: SignedDigit, + carry: bool, +) -> (SignedDigit, bool) { + let (s1, o1) = a.overflowing_add(b); + if carry { + let (s2, o2) = s1.overflowing_add(1); + (s2, o1 != o2) + } else { + (s1, o1) + } +} + +#[inline] +pub const fn borrowing_sub_signed( + a: SignedDigit, + b: SignedDigit, + borrow: bool, +) -> (SignedDigit, bool) { + let (s1, o1) = a.overflowing_sub(b); + if borrow { + let (s2, o2) = s1.overflowing_sub(1); + (s2, o1 != o2) + } else { + (s1, o1) + } +} + +#[inline] +pub const fn widening_mul(a: Digit, b: Digit) -> (Digit, Digit) { + let prod = a as DoubleDigit * b as DoubleDigit; + (prod as Digit, (prod >> BITS) as Digit) +} + +#[inline] +pub const fn carrying_mul( + a: Digit, + b: Digit, + carry: Digit, + current: Digit, +) -> (Digit, Digit) { + let prod = carry as DoubleDigit + + current as DoubleDigit + + (a as DoubleDigit) * (b as DoubleDigit); + (prod as Digit, (prod >> BITS) as Digit) +} + +#[inline] +pub const fn div_rem_wide(low: Digit, high: Digit, rhs: Digit) -> (Digit, Digit) { + debug_assert!(high < rhs); + + let a = to_double_digit(low, high); + ( + (a / rhs as DoubleDigit) as Digit, + (a % rhs as DoubleDigit) as Digit, + ) } -digit_module!(u8, i8, u16); -digit_module!(u16, i16, u32); -digit_module!(u32, i32, u64); -digit_module!(u64, i64, u128); +pub const HEX_PADDING: usize = BITS as usize / 4; diff --git a/src/doc/consts.rs b/src/doc/consts.rs index 0e4c5ab..aa0f8b0 100644 --- a/src/doc/consts.rs +++ b/src/doc/consts.rs @@ -108,4 +108,4 @@ pub(crate) use value_desc; // NAN, // INFINITY, // NEG_INFINITY -// ); \ No newline at end of file +// ); diff --git a/src/errors/macros.rs b/src/errors/macros.rs index cbc20c7..9f37b60 100644 --- a/src/errors/macros.rs +++ b/src/errors/macros.rs @@ -24,7 +24,9 @@ pub(crate) use div_by_zero_message; macro_rules! div_zero { () => { - panic!(crate::errors::err_msg!(crate::errors::div_by_zero_message!())) + panic!(crate::errors::err_msg!( + crate::errors::div_by_zero_message!() + )) }; } @@ -41,7 +43,7 @@ pub(crate) use rem_by_zero_message; macro_rules! non_positive_log_message { () => { "argument of integer logarithm must be positive" - } + }; } pub(crate) use non_positive_log_message; @@ -49,14 +51,16 @@ pub(crate) use non_positive_log_message; macro_rules! invalid_log_base { () => { "base of integer logarithm must be at least 2" - } + }; } pub(crate) use invalid_log_base; macro_rules! rem_zero { () => { - panic!(crate::errors::err_msg!(crate::errors::rem_by_zero_message!())) + panic!(crate::errors::err_msg!( + crate::errors::rem_by_zero_message!() + )) }; } diff --git a/src/errors/parseint.rs b/src/errors/parseint.rs index a2aa8f7..26ebb76 100644 --- a/src/errors/parseint.rs +++ b/src/errors/parseint.rs @@ -28,7 +28,8 @@ impl ParseIntError { "attempt to parse integer too small to be represented by the target type" } IntErrorKind::Zero => { - "attempt to parse the integer `0` which cannot be represented by the target type" // for now this should never occur, unless we implement NonZeroU... types + "attempt to parse the integer `0` which cannot be represented by the target type" + // for now this should never occur, unless we implement NonZeroU... types } _ => panic!("unsupported `IntErrorKind` variant"), // necessary as `IntErrorKind` is non-exhaustive } diff --git a/src/float/cast.rs b/src/float/cast.rs index 2733d2c..34a9ef7 100644 --- a/src/float/cast.rs +++ b/src/float/cast.rs @@ -42,10 +42,10 @@ macro_rules! int_as_float { int_as_float!(i8, i16, i32, i64, i128, isize); macro_rules! bint_as_float { - ($($bint: ident), *) => { + ($(BIntD8: ident), *) => { $( - impl CastFrom<$bint> for Float { - fn cast_from(from: $bint) -> Self { + impl CastFrom> for Float { + fn cast_from(from: BIntD8) -> Self { let pos_cast = Self::cast_from(from.unsigned_abs()); if from.is_negative() { -pos_cast @@ -60,16 +60,12 @@ macro_rules! bint_as_float { bint_as_float!(BIntD8, BIntD16, BIntD32, BInt); -macro_rules! float_as_bint { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl CastFrom> for $BInt { - crate::bint::cast::bint_cast_from_float!(Float, $BUint); + impl CastFrom> for BIntD8 { + crate::bint::cast::bint_cast_from_float!(Float, BUintD8); } }; } -crate::macro_impl!(float_as_bint); - macro_rules! float_as_int { ($($int: ty; $uint: ty), *) => { $( diff --git a/src/helpers.rs b/src/helpers.rs index 09f7ceb..f0f1f90 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -27,26 +27,20 @@ macro_rules! impl_bits_for_uint { impl_bits_for_uint!(u8, u16, u32, u64, u128, usize); -macro_rules! impl_bits_for_buint { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl crate::helpers::Bits for $BUint { - const BITS: ExpType = Self::BITS; +impl crate::helpers::Bits for crate::BUintD8 { + const BITS: ExpType = Self::BITS; - #[inline] - fn bits(&self) -> ExpType { - Self::bits(&self) - } + #[inline] + fn bits(&self) -> ExpType { + Self::bits(&self) + } - #[inline] - fn bit(&self, index: ExpType) -> bool { - Self::bit(&self, index) - } - } - }; + #[inline] + fn bit(&self, index: ExpType) -> bool { + Self::bit(&self, index) + } } -crate::macro_impl!(impl_bits_for_buint); - pub trait Zero: Sized + PartialEq { const ZERO: Self; @@ -83,26 +77,14 @@ macro_rules! impl_one_for_int { impl_one_for_int!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); -macro_rules! impl_zero_for_buint { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl crate::helpers::Zero for $BUint { - const ZERO: Self = Self::ZERO; - } - }; +impl crate::helpers::Zero for crate::BUintD8 { + const ZERO: Self = Self::ZERO; } -crate::macro_impl!(impl_zero_for_buint); - -macro_rules! impl_one_for_buint { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl crate::helpers::One for $BUint { - const ONE: Self = Self::ONE; - } - }; +impl crate::helpers::One for crate::BUintD8 { + const ONE: Self = Self::ONE; } -crate::macro_impl!(impl_one_for_buint); - #[inline] pub const fn tuple_to_option((int, overflow): (T, bool)) -> Option { if overflow { diff --git a/src/int/cast.rs b/src/int/cast.rs index ad5bdc2..1d6879e 100644 --- a/src/int/cast.rs +++ b/src/int/cast.rs @@ -50,4 +50,4 @@ macro_rules! test_cast_to_bigint { } #[cfg(test)] -pub(crate) use test_cast_to_bigint; \ No newline at end of file +pub(crate) use test_cast_to_bigint; diff --git a/src/int/checked.rs b/src/int/checked.rs index e69de29..8b13789 100644 --- a/src/int/checked.rs +++ b/src/int/checked.rs @@ -0,0 +1 @@ + diff --git a/src/int/numtraits.rs b/src/int/numtraits.rs index 3c2333a..14ac9c2 100644 --- a/src/int/numtraits.rs +++ b/src/int/numtraits.rs @@ -42,7 +42,7 @@ macro_rules! as_bigint_impl { pub(crate) use as_bigint_impl; macro_rules! impls { - ($Int: ident, $BUint: ident, $BInt: ident, $Digit: ident) => { + ($Int: ident) => { impl Bounded for $Int { #[inline] fn min_value() -> Self { @@ -160,24 +160,24 @@ macro_rules! impls { crate::int::numtraits::as_bigint_impl!([u8, u16, u32, usize, u64, u128, i8, i16, i32, isize, i64, i128, char, bool, f32, f64] as $Int); - impl AsPrimitive<$BUint> for $Int { + impl AsPrimitive> for $Int { #[inline] - fn as_(self) -> crate::$BUint { - crate::$BUint::::cast_from(self) + fn as_(self) -> crate::BUintD8 { + crate::BUintD8::::cast_from(self) } } - impl AsPrimitive<$BInt> for $Int { + impl AsPrimitive> for $Int { #[inline] - fn as_(self) -> crate::$BInt { - crate::$BInt::::cast_from(self) + fn as_(self) -> crate::BIntD8 { + crate::BIntD8::::cast_from(self) } } // #[cfg(feature = "nightly")] // #[doc = crate::doc::requires_feature!("nightly")] // impl FromBytes for $Int { - // type Bytes = [u8; $BUint::::BYTES_USIZE]; + // type Bytes = [u8; BUintD8::::BYTES_USIZE]; // #[inline] // fn from_be_bytes(&self) -> Self::BYTES { @@ -198,7 +198,7 @@ macro_rules! impls { // #[cfg(feature = "nightly")] // #[doc = crate::doc::requires_feature!("nightly")] // impl ToBytes for $Int { - // type Bytes = [u8; $BUint::::BYTES_USIZE]; + // type Bytes = [u8; BUintD8::::BYTES_USIZE]; // #[inline] // fn to_be_bytes(&self) -> Self::BYTES { diff --git a/src/int/ops.rs b/src/int/ops.rs index 1c927f0..7111775 100644 --- a/src/int/ops.rs +++ b/src/int/ops.rs @@ -68,7 +68,7 @@ macro_rules! shift_impl { pub(crate) use shift_impl; macro_rules! try_shift_impl { - ($Struct: ident, $BUint: ident, $BInt: ident; $tr: tt, $method: ident, $assign_tr: tt, $assign_method: ident, $err: expr, $($rhs: ty), *) => { + ($Struct: ident; $tr: tt, $method: ident, $assign_tr: tt, $assign_method: ident, $err: expr, $($rhs: ty), *) => { $( impl $tr<$rhs> for $Struct { type Output = Self; @@ -90,14 +90,17 @@ macro_rules! try_shift_impl { 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) => { + ($Struct: ident; $tr: tt<$rhs: tt>, $method: ident, $assign_tr: tt, $assign_method: ident, $err: expr) => { impl $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)); + let rhs: ExpType = crate::errors::result_expect!( + ExpType::try_from(rhs), + crate::errors::err_msg!($err) + ); self.$method(rhs) } } @@ -142,14 +145,14 @@ macro_rules! shift_self_impl { (*self).$assign_method(*rhs); } } - } + }; } pub(crate) use shift_self_impl; macro_rules! all_shift_impls { - ($Struct: ident, $BUint: ident, $BInt: ident) => { + ($Struct: ident) => { crate::int::ops::try_shift_impl!( - $Struct, $BUint, $BInt; + $Struct; Shl, shl, ShlAssign, @@ -164,7 +167,7 @@ macro_rules! all_shift_impls { ); crate::int::ops::try_shift_impl!( - $Struct, $BUint, $BInt; + $Struct; Shr, shr, ShrAssign, @@ -183,7 +186,7 @@ macro_rules! all_shift_impls { crate::int::ops::shift_impl!($Struct, Shr, shr, ShrAssign, shr_assign, u8, u16); crate::int::ops::try_shift_impl!( - $Struct, $BUint, $BInt; + $Struct; Shl, shl, ShlAssign, @@ -195,7 +198,7 @@ macro_rules! all_shift_impls { ); crate::int::ops::try_shift_impl!( - $Struct, $BUint, $BInt; + $Struct; Shr, shr, ShrAssign, @@ -207,8 +210,8 @@ macro_rules! all_shift_impls { ); crate::int::ops::shift_self_impl!( - $Struct, $BUint, $BInt; - Shl<$BUint>, + $Struct; + Shl, shl, ShlAssign, shl_assign, @@ -216,8 +219,8 @@ macro_rules! all_shift_impls { ); crate::int::ops::shift_self_impl!( - $Struct, $BUint, $BInt; - Shr<$BUint>, + $Struct; + Shr, shr, ShrAssign, shr_assign, @@ -225,8 +228,8 @@ macro_rules! all_shift_impls { ); crate::int::ops::shift_self_impl!( - $Struct, $BUint, $BInt; - Shl<$BInt>, + $Struct; + Shl, shl, ShlAssign, shl_assign, @@ -234,8 +237,8 @@ macro_rules! all_shift_impls { ); crate::int::ops::shift_self_impl!( - $Struct, $BUint, $BInt; - Shr<$BInt>, + $Struct; + Shr, shr, ShrAssign, shr_assign, @@ -307,7 +310,7 @@ macro_rules! trait_fillers { pub(crate) use trait_fillers; macro_rules! impls { - ($Struct: ident, $BUint: ident, $BInt: ident) => { + ($Struct: ident) => { impl Add for $Struct { type Output = Self; @@ -353,7 +356,7 @@ macro_rules! impls { } } - crate::int::ops::all_shift_impls!($Struct, $BUint, $BInt); + crate::int::ops::all_shift_impls!($Struct); impl Sub for $Struct { type Output = Self; diff --git a/src/int/strict.rs b/src/int/strict.rs index 05b1b4a..90092e9 100644 --- a/src/int/strict.rs +++ b/src/int/strict.rs @@ -63,7 +63,8 @@ macro_rules! impls { #[inline] pub const fn strict_neg(self) -> Self { crate::errors::option_expect!( - self.checked_neg(), crate::errors::err_msg!("attempt to negate with overflow") + self.checked_neg(), + crate::errors::err_msg!("attempt to negate with overflow") ) } @@ -95,8 +96,8 @@ macro_rules! impls { self.checked_pow(exp), crate::errors::err_msg!("attempt to calculate power with overflow") ) - } - } + } + }; } pub(crate) use impls; @@ -150,7 +151,7 @@ macro_rules! tests { function: <$int>::strict_pow(a: $int, b: u8), skip: a.checked_pow(b as u32).is_none() } - } + }; } #[cfg(test)] diff --git a/src/int/unchecked.rs b/src/int/unchecked.rs index cd49740..3562ffc 100644 --- a/src/int/unchecked.rs +++ b/src/int/unchecked.rs @@ -69,8 +69,8 @@ macro_rules! tests { function: unsafe <$int>::unchecked_shr(a: $int, b: u8), skip: a.checked_shr(b as u32).is_none() } - } + }; } #[cfg(test)] -pub(crate) use tests; \ No newline at end of file +pub(crate) use tests; diff --git a/src/lib.rs b/src/lib.rs index 60506a7..10659db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,7 @@ #![cfg_attr(feature = "nightly", allow(incomplete_features))] #![cfg_attr( feature = "nightly", - feature( - generic_const_exprs, - const_trait_impl, - const_option, - ) + feature(generic_const_exprs, const_trait_impl, const_option,) )] #![cfg_attr( test, @@ -35,8 +31,8 @@ pub mod cast; mod digit; mod doc; pub mod errors; -mod int; mod helpers; +mod int; mod nightly; pub mod prelude; @@ -59,53 +55,17 @@ use test::types::*; type ExpType = u32; -mod bigints { - pub use crate::bint::{BInt, BIntD16, BIntD32, BIntD8}; - pub use crate::buint::{BUint, BUintD16, BUintD32, BUintD8}; -} - -pub use bigints::*; +pub use buint::BUintD8; +pub use bint::BIntD8; -macro_rules! macro_impl { - ($name: ident) => { - #[allow(unused_imports)] - use crate::bigints::*; - - crate::main_impl!($name); - }; -} +type Digit = u8; -pub(crate) use macro_impl; - -macro_rules! main_impl { - ($name: ident) => { - $name!(BUint, BInt, u64); - $name!(BUintD32, BIntD32, u32); - $name!(BUintD16, BIntD16, u16); - $name!(BUintD8, BIntD8, u8); - }; -} - -use crate::buint::cast::buint_as_different_digit_bigint; -use crate::bint::cast::bint_as_different_digit_bigint; - -buint_as_different_digit_bigint!(BUint, BInt, u64; (BUintD32, u32), (BUintD16, u16), (BUintD8, u8)); -buint_as_different_digit_bigint!(BUintD32, BIntD32, u32; (BUint, u64), (BUintD16, u16), (BUintD8, u8)); -buint_as_different_digit_bigint!(BUintD16, BIntD16, u16; (BUint, u64), (BUintD32, u32), (BUintD8, u8)); -buint_as_different_digit_bigint!(BUintD8, BIntD8, u8; (BUint, u64), (BUintD32, u32), (BUintD16, u16)); - -bint_as_different_digit_bigint!(BUint, BInt, u64; (BIntD32, u32), (BIntD16, u16), (BIntD8, u8)); -bint_as_different_digit_bigint!(BUintD32, BIntD32, u32; (BInt, u64), (BIntD16, u16), (BIntD8, u8)); -bint_as_different_digit_bigint!(BUintD16, BIntD16, u16; (BInt, u64), (BIntD32, u32), (BIntD8, u8)); -bint_as_different_digit_bigint!(BUintD8, BIntD8, u8; (BInt, u64), (BIntD32, u32), (BIntD16, u16)); - -pub(crate) use main_impl; /// Trait for fallible conversions between `bnum` integer types. -/// +/// /// Unfortunately, [`TryFrom`] cannot currently be used for conversions between `bnum` integers, since [`TryFrom for T`](https://doc.rust-lang.org/std/convert/trait.TryFrom.html#impl-TryFrom%3CU%3E-for-T) is already implemented by the standard library (and so it is not possible to implement `TryFrom> for BUint`). When the [`generic_const_exprs`](https://github.com/rust-lang/rust/issues/76560) feature becomes stabilised, it may be possible to use [`TryFrom`] instead of `BTryFrom`. `BTryFrom` is designed to have the same behaviour as [`TryFrom`] for conversions between two primitive types, and conversions between a primitive type and a bnum type. `BTryFrom` is a workaround for the issue described above, and so you should not implement it yourself. It should only be used for conversions between `bnum` integers. pub trait BTryFrom: Sized { type Error; fn try_from(from: T) -> Result; -} \ No newline at end of file +} diff --git a/src/prelude.rs b/src/prelude.rs index 31813c0..c8d1271 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,5 +1,5 @@ //! A collection of common use items. pub use crate::cast::{As, CastFrom}; -pub use crate::BInt; -pub use crate::BUint; +pub use crate::BIntD8; +pub use crate::BUintD8; diff --git a/src/random.rs b/src/random.rs index 24b1a4e..85519be 100644 --- a/src/random.rs +++ b/src/random.rs @@ -299,36 +299,33 @@ pub struct UniformInt { use rand::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler}; use rand::distributions::{Distribution, Standard}; use rand::{Error, Fill, Rng}; +use crate::{BUintD8, BIntD8}; + +impl Distribution> for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> BUintD8 { + let mut digits = [0; N]; + rng.fill(&mut digits); + BUintD8::from_digits(digits) + } +} -macro_rules! random { - ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl Distribution<$BUint> for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> $BUint { - let mut digits = [0; N]; - rng.fill(&mut digits); - $BUint::from_digits(digits) - } - } - - impl Distribution<$BInt> for Standard { - #[inline] - fn sample(&self, rng: &mut R) -> $BInt { - $BInt::from_bits(rng.gen()) - } - } +impl Distribution> for Standard { + #[inline] + fn sample(&self, rng: &mut R) -> BIntD8 { + BIntD8::from_bits(rng.gen()) + } +} - fill_impl!($BUint); - fill_impl!($BInt); +fill_impl!(BUintD8); +fill_impl!(BIntD8); - uniform_int_impl!($BUint, $BUint); +uniform_int_impl!(BUintD8, BUintD8); - uniform_int_impl!($BInt, $BUint, to_bits, from_bits); - }; -} +uniform_int_impl!(BIntD8, BUintD8, to_bits, from_bits); #[cfg(test)] -crate::test::all_digit_tests! { +mod tests { use crate::test::types::*; use rand::SeedableRng; @@ -341,5 +338,3 @@ crate::test::all_digit_tests! { test_random!(utest; StdRng, SmallRng); test_random!(itest; StdRng, SmallRng); } - -crate::macro_impl!(random); diff --git a/src/test/convert.rs b/src/test/convert.rs index 5a33a0d..f77582d 100644 --- a/src/test/convert.rs +++ b/src/test/convert.rs @@ -11,9 +11,9 @@ pub trait TestConvert { #[allow(unused)] // since this is only used with certain crate feature but these are likely to change often pub fn test_eq(t: T, u: U) -> bool where -T: TestConvert, -U: TestConvert, -::Output: PartialEq<::Output> + T: TestConvert, + U: TestConvert, + ::Output: PartialEq<::Output>, { t.into() == u.into() } @@ -37,9 +37,9 @@ macro_rules! test_convert_bigints { ($($bits: literal), *) => { paste::paste! { $( - test_convert_big!(BUint<{$bits / 64}>, BUintD32<{$bits / 32}>, BUintD16<{$bits / 16}>, BUintD8<{$bits / 8}>; []); + test_convert_big!(BUintD8<{$bits / 8}>; []); - test_convert_big!(BInt<{$bits / 64}>, BIntD32<{$bits / 32}>, BIntD16<{$bits / 16}>, BIntD8<{$bits / 8}>; []); + test_convert_big!(BIntD8<{$bits / 8}>; []); )* } }; @@ -47,10 +47,10 @@ macro_rules! test_convert_bigints { test_convert_bigints!(128, 64); -test_convert_big!(BUintD32<{32 / 32}>, BUintD16<{32 / 16}>, BUintD8<{32 / 8}>; u32); -test_convert_big!(BIntD32<{32 / 32}>, BIntD16<{32 / 16}>, BIntD8<{32 / 8}>; i32); -test_convert_big!(BUintD16<{16 / 16}>, BUintD8<{16 / 8}>; u16); -test_convert_big!(BIntD16<{16 / 16}>, BIntD8<{16 / 8}>; i16); +test_convert_big!(BUintD8<{32 / 8}>; u32); +test_convert_big!(BIntD8<{32 / 8}>; i32); +test_convert_big!(BUintD8<{16 / 8}>; u16); +test_convert_big!(BIntD8<{16 / 8}>; i16); impl TestConvert for Option { type Output = Option<::Output>; @@ -144,9 +144,7 @@ impl TestConvert for Result { #[inline] fn into(self) -> Self::Output { - self - .map(TestConvert::into) - .map_err(TestConvert::into) + self.map(TestConvert::into).map_err(TestConvert::into) } } diff --git a/src/test/macros.rs b/src/test/macros.rs index b33468a..b056741 100644 --- a/src/test/macros.rs +++ b/src/test/macros.rs @@ -216,7 +216,7 @@ macro_rules! quickcheck_from_str_radix { let (big, primitive) = crate::test::results!(<$primitive>::from_str_radix(&s2, radix as u32)); - // let parsed = + // let parsed = quickcheck::TestResult::from_bool(big == primitive) } @@ -243,33 +243,3 @@ macro_rules! quickcheck_from_str { } pub(crate) use quickcheck_from_str; - -macro_rules! digit_tests { - { use $Digit: ident digit; $($test_content: tt)* } => { - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::types::big_types::$Digit::*; - - $($test_content)* - } - } - }; -} - -pub(crate) use digit_tests; - -macro_rules! all_digit_tests { - { $($test_content: tt)* } => { - crate::test::digit_tests! { use u8 digit; $($test_content)* } - - crate::test::digit_tests! { use u16 digit; $($test_content)* } - - #[cfg(not(test_int_bits = "16"))] - crate::test::digit_tests! { use u32 digit; $($test_content)* } - - #[cfg(not(any(test_int_bits = "16", test_int_bits = "32")))] - crate::test::digit_tests! { use u64 digit; $($test_content)* } - } -} - -pub(crate) use all_digit_tests; \ No newline at end of file diff --git a/src/test/mod.rs b/src/test/mod.rs index 042994a..28fbda3 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -38,32 +38,27 @@ impl Debug for U8ArrayWrapper { } pub mod cast_types { - use crate::{BUint, BUintD32, BUintD16, BUintD8, BInt, BIntD32, BIntD16, BIntD8}; + use crate::{BIntD8, BUintD8}; - pub use crate::big_types::u8::{UTEST as UTESTD8, ITEST as ITESTD8}; - pub use crate::big_types::u16::{UTEST as UTESTD16, ITEST as ITESTD16}; - pub use crate::big_types::u32::{UTEST as UTESTD32, ITEST as ITESTD32}; - pub use crate::big_types::u64::{UTEST as UTESTD64, ITEST as ITESTD64}; - - pub type TestUint1 = BUint<3>; - pub type TestUint2 = BUintD32<5>; - pub type TestUint3 = BUintD16<6>; + pub type TestUint1 = BUintD8<10>; + pub type TestUint2 = BUintD8<8>; + pub type TestUint3 = BUintD8<6>; pub type TestUint4 = BUintD8<11>; - pub type TestUint5 = BUintD16<3>; + pub type TestUint5 = BUintD8<5>; pub type TestUint6 = BUintD8<7>; pub type TestUint7 = BUintD8<3>; - pub type TestUint8 = BUintD16<1>; + pub type TestUint8 = BUintD8<1>; pub type TestUint9 = BUintD8<15>; pub type TestUint10 = BUintD8<17>; - pub type TestInt1 = BInt<3>; - pub type TestInt2 = BIntD32<5>; - pub type TestInt3 = BIntD16<6>; + pub type TestInt1 = BIntD8<10>; + pub type TestInt2 = BIntD8<8>; + pub type TestInt3 = BIntD8<6>; pub type TestInt4 = BIntD8<11>; - pub type TestInt5 = BIntD16<3>; + pub type TestInt5 = BIntD8<5>; pub type TestInt6 = BIntD8<7>; pub type TestInt7 = BIntD8<3>; - pub type TestInt8 = BIntD16<1>; + pub type TestInt8 = BIntD8<1>; pub type TestInt9 = BIntD8<15>; pub type TestInt10 = BIntD8<17>; -} \ No newline at end of file +} diff --git a/src/test/types.rs b/src/test/types.rs index e3a4323..0563c7a 100644 --- a/src/test/types.rs +++ b/src/test/types.rs @@ -1,92 +1,37 @@ -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! test_types { + ($bits: literal) => { + paste::paste! { + mod types { + #[allow(non_camel_case_types)] + pub type utest = []; - #[cfg(test_int_bits = "16")] - big_types_modules!(16); + #[allow(non_camel_case_types)] + pub type itest = []; - #[cfg(test_int_bits = "32")] - big_types_modules!(32); - - #[cfg(test_int_bits = "128")] - big_types_modules!(128); + #[allow(non_camel_case_types)] + pub type UTEST = crate::BUintD8<{ $bits / 8 }>; - #[cfg(not(any(test_int_bits = "16", test_int_bits = "32", test_int_bits = "128")))] - big_types_modules!(64); + #[allow(non_camel_case_types)] + pub type ITEST = crate::BIntD8<{ $bits / 8 }>; + } + } + }; } #[cfg(test_int_bits = "16")] -mod small_types { - #[allow(non_camel_case_types)] - pub type utest = u16; - - #[allow(non_camel_case_types)] - pub type itest = i16; - - // #[cfg(feature = "float")] - // #[allow(non_camel_case_types)] - // pub type ftest = f16; -} +test_types!(16); #[cfg(test_int_bits = "32")] -mod small_types { - #[allow(non_camel_case_types)] - pub type utest = u32; - - #[allow(non_camel_case_types)] - pub type itest = i32; - - // #[cfg(feature = "float")] - // #[allow(non_camel_case_types)] - // pub type ftest = f32; -} +test_types!(32); #[cfg(test_int_bits = "128")] -mod small_types { - #[allow(non_camel_case_types)] - pub type utest = u128; - - #[allow(non_camel_case_types)] - pub type itest = i128; +test_types!(128); - // #[cfg(feature = "float")] - // #[allow(non_camel_case_types)] - // pub type ftest = f128; -} - -#[cfg(not(any(test_int_bits = "16", test_int_bits = "32", test_int_bits = "128")))] // default is 64 -mod small_types { - #[allow(non_camel_case_types)] - pub type utest = u64; - - #[allow(non_camel_case_types)] - pub type itest = i64; - - // #[cfg(feature = "float")] - // #[allow(non_camel_case_types)] - // pub type ftest = f64; -} +#[cfg(not(any(test_int_bits = "16", test_int_bits = "32", test_int_bits = "128")))] +test_types!(64); +pub use types::*; pub use core::primitive::*; -pub use small_types::*; // #[cfg(feature = "float")] // #[cfg(not(test_int_bits = "32"))] @@ -94,4 +39,4 @@ pub use small_types::*; // #[cfg(feature = "float")] // #[cfg(test_int_bits = "32")] -// 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 929cc39..9b6d4cf 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,6 @@ //! Type aliases for big signed and unsigned integers. Each is an alias for either a [`BUint`] or a [`BInt`]. -use crate::{BInt, BUint}; +use crate::{BIntD8, BUintD8}; macro_rules! int_type_doc { ($bits: literal, $sign: literal) => { @@ -12,10 +12,10 @@ macro_rules! int_types { { $($bits: literal $u: ident $i: ident; ) *} => { $( #[doc = int_type_doc!($bits, "unsigned")] - pub type $u = BUint::<{$bits / 64}>; + pub type $u = BUintD8::<{$bits / 8}>; #[doc = int_type_doc!($bits, "signed")] - pub type $i = BInt::<{$bits / 64}>; + pub type $i = BIntD8::<{$bits / 8}>; )* }; }