From 7a3f52e46142300f5029dc01cb61c5ed679b93da Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:57:36 -0600 Subject: [PATCH 01/12] v0.1.0 Release From 06cd2e3260d317d04ae9cd4d7a5c982c5468f8eb Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 02/12] Refactor impl_count_digits --- src/lib.rs | 138 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 44 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a49a8b8cf..c4d2430b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -225,76 +225,126 @@ pub trait CountDigits: Copy + Sized { } macro_rules! impl_count_digits { - (signed, $type:ty) => { - impl CountDigits for $type { + ( + primitive_type = $primitive_type:ty, + non_zero_type = $non_zero_type:ty, + ) => { + impl CountDigits for $primitive_type { #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { - self.abs_diff(0).checked_ilog10().unwrap_or_default() + 1 + 1 + self.abs_diff(0).checked_ilog10().unwrap_or_default() } } - }; - (unsigned, $type:ty) => { - impl CountDigits for $type { + impl CountDigits for $non_zero_type { #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { - self.checked_ilog10().unwrap_or_default() + 1 + 1 + self.get().abs_diff(0).ilog10() } } }; -} - -macro_rules! impl_nonzero_count_digits { - (signed, $type:ty) => { - impl CountDigits for $type { + ( + primitive_type = $primitive_type:ty, + non_zero_type = $non_zero_type:ty, + ) => { + impl CountDigits for $primitive_type { #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { - self.get().abs_diff(0).ilog10() + 1 + 1 + self.checked_ilog10().unwrap_or_default() } } - }; - (unsigned, $type:ty) => { - impl CountDigits for $type { + impl CountDigits for $non_zero_type { #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { - self.ilog10() + 1 + 1 + self.ilog10() } } }; } -impl_count_digits!(signed, i8); -impl_count_digits!(signed, i16); -impl_count_digits!(signed, i32); -impl_count_digits!(signed, i64); -impl_count_digits!(signed, i128); -impl_count_digits!(signed, isize); - -impl_count_digits!(unsigned, u8); -impl_count_digits!(unsigned, u16); -impl_count_digits!(unsigned, u32); -impl_count_digits!(unsigned, u64); -impl_count_digits!(unsigned, u128); -impl_count_digits!(unsigned, usize); - -impl_nonzero_count_digits!(signed, NonZeroI8); -impl_nonzero_count_digits!(signed, NonZeroI16); -impl_nonzero_count_digits!(signed, NonZeroI32); -impl_nonzero_count_digits!(signed, NonZeroI64); -impl_nonzero_count_digits!(signed, NonZeroI128); -impl_nonzero_count_digits!(signed, NonZeroIsize); - -impl_nonzero_count_digits!(unsigned, NonZeroU8); -impl_nonzero_count_digits!(unsigned, NonZeroU16); -impl_nonzero_count_digits!(unsigned, NonZeroU32); -impl_nonzero_count_digits!(unsigned, NonZeroU64); -impl_nonzero_count_digits!(unsigned, NonZeroU128); -impl_nonzero_count_digits!(unsigned, NonZeroUsize); +impl_count_digits! { + primitive_type = i8, + non_zero_type = NonZeroI8, +} + +impl_count_digits! { + primitive_type = i16, + non_zero_type = NonZeroI16, +} + +impl_count_digits! { + primitive_type = i32, + non_zero_type = NonZeroI32, +} + +impl_count_digits! { + primitive_type = i64, + non_zero_type = NonZeroI64, +} + +impl_count_digits! { + primitive_type = i128, + non_zero_type = NonZeroI128, +} + +#[cfg(target_pointer_width = "64")] +impl_count_digits! { + primitive_type = isize, + non_zero_type = NonZeroIsize, +} + +#[cfg(target_pointer_width = "32")] +impl_count_digits! { + primitive_type = isize, + non_zero_type = NonZeroIsize, +} + +#[cfg(target_pointer_width = "16")] +impl_count_digits! { + primitive_type = isize, + non_zero_type = NonZeroIsize, +} + +#[cfg(target_pointer_width = "8")] +impl_count_digits! { + primitive_type = isize, + non_zero_type = NonZeroIsize, +} + +impl_count_digits! { + primitive_type = u8, + non_zero_type = NonZeroU8, +} + +impl_count_digits! { + primitive_type = u16, + non_zero_type = NonZeroU16, +} + +impl_count_digits! { + primitive_type = u32, + non_zero_type = NonZeroU32, +} + +impl_count_digits! { + primitive_type = u64, + non_zero_type = NonZeroU64, +} + +impl_count_digits! { + primitive_type = u128, + non_zero_type = NonZeroU128, +} + +impl_count_digits! { + primitive_type = usize, + non_zero_type = NonZeroUsize, +} #[cfg(test)] mod count_digits { From 1b500eb44cf4747fe0153a6335f0c383cf2551ee Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 03/12] Implement CountDigits::count_bits() --- src/lib.rs | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index c4d2430b6..b0bfe4b86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,6 +116,112 @@ use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZ /// Count the decimal digits of an integer. pub trait CountDigits: Copy + Sized { + /// Returns the count of bits in an integer starting with the first non-zero bit. + /// ```rust + /// use count_digits::CountDigits; + /// # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; + /// # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + /// + /// assert_eq!(008, i8::MIN.count_bits()); + /// assert_eq!(007, i8::MAX.count_bits()); + /// assert_eq!(008, NonZeroI8::MIN.count_bits()); + /// assert_eq!(007, NonZeroI8::MAX.count_bits()); + /// + /// assert_eq!(001, u8::MIN.count_bits()); + /// assert_eq!(008, u8::MAX.count_bits()); + /// assert_eq!(001, NonZeroU8::MIN.count_bits()); + /// assert_eq!(008, NonZeroU8::MAX.count_bits()); + /// + /// assert_eq!(016, i16::MIN.count_bits()); + /// assert_eq!(015, i16::MAX.count_bits()); + /// assert_eq!(016, NonZeroI16::MIN.count_bits()); + /// assert_eq!(015, NonZeroI16::MAX.count_bits()); + /// + /// assert_eq!(001, u16::MIN.count_bits()); + /// assert_eq!(016, u16::MAX.count_bits()); + /// assert_eq!(001, NonZeroU16::MIN.count_bits()); + /// assert_eq!(016, NonZeroU16::MAX.count_bits()); + /// + /// assert_eq!(032, i32::MIN.count_bits()); + /// assert_eq!(031, i32::MAX.count_bits()); + /// assert_eq!(032, NonZeroI32::MIN.count_bits()); + /// assert_eq!(031, NonZeroI32::MAX.count_bits()); + /// + /// assert_eq!(001, u32::MIN.count_bits()); + /// assert_eq!(032, u32::MAX.count_bits()); + /// assert_eq!(001, NonZeroU32::MIN.count_bits()); + /// assert_eq!(032, NonZeroU32::MAX.count_bits()); + /// + /// assert_eq!(064, i64::MIN.count_bits()); + /// assert_eq!(063, i64::MAX.count_bits()); + /// assert_eq!(064, NonZeroI64::MIN.count_bits()); + /// assert_eq!(063, NonZeroI64::MAX.count_bits()); + /// + /// assert_eq!(001, u64::MIN.count_bits()); + /// assert_eq!(064, u64::MAX.count_bits()); + /// assert_eq!(001, NonZeroU64::MIN.count_bits()); + /// assert_eq!(064, NonZeroU64::MAX.count_bits()); + /// + /// assert_eq!(128, i128::MIN.count_bits()); + /// assert_eq!(127, i128::MAX.count_bits()); + /// assert_eq!(128, NonZeroI128::MIN.count_bits()); + /// assert_eq!(127, NonZeroI128::MAX.count_bits()); + /// + /// assert_eq!(001, u128::MIN.count_bits()); + /// assert_eq!(128, u128::MAX.count_bits()); + /// assert_eq!(001, NonZeroU128::MIN.count_bits()); + /// assert_eq!(128, NonZeroU128::MAX.count_bits()); + /// + /// #[cfg(target_pointer_width = "64")] { + /// assert_eq!(isize::MIN.count_bits(), i64::MIN.count_bits()); + /// assert_eq!(isize::MAX.count_bits(), i64::MAX.count_bits()); + /// assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI64::MIN.count_bits()); + /// assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI64::MAX.count_bits()); + /// + /// assert_eq!(usize::MIN.count_bits(), u64::MIN.count_bits()); + /// assert_eq!(usize::MAX.count_bits(), u64::MAX.count_bits()); + /// assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU64::MIN.count_bits()); + /// assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU64::MAX.count_bits()); + /// } + /// + /// #[cfg(target_pointer_width = "32")] { + /// assert_eq!(isize::MIN.count_bits(), i32::MIN.count_bits()); + /// assert_eq!(isize::MAX.count_bits(), i32::MAX.count_bits()); + /// assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI32::MIN.count_bits()); + /// assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI32::MAX.count_bits()); + /// + /// assert_eq!(usize::MIN.count_bits(), u32::MIN.count_bits()); + /// assert_eq!(usize::MAX.count_bits(), u32::MAX.count_bits()); + /// assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU32::MIN.count_bits()); + /// assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU32::MAX.count_bits()); + /// } + /// + /// #[cfg(target_pointer_width = "16")] { + /// assert_eq!(isize::MIN.count_bits(), i16::MIN.count_bits()); + /// assert_eq!(isize::MAX.count_bits(), i16::MAX.count_bits()); + /// assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI16::MIN.count_bits()); + /// assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI16::MAX.count_bits()); + /// + /// assert_eq!(usize::MIN.count_bits(), u16::MIN.count_bits()); + /// assert_eq!(usize::MAX.count_bits(), u16::MAX.count_bits()); + /// assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU16::MIN.count_bits()); + /// assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU16::MAX.count_bits()); + /// } + /// + /// #[cfg(target_pointer_width = "8")] { + /// assert_eq!(isize::MIN.count_bits(), i8::MIN.count_bits()); + /// assert_eq!(isize::MAX.count_bits(), i8::MAX.count_bits()); + /// assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI8::MIN.count_bits()); + /// assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI8::MAX.count_bits()); + /// + /// assert_eq!(usize::MIN.count_bits(), u8::MIN.count_bits()); + /// assert_eq!(usize::MAX.count_bits(), u8::MAX.count_bits()); + /// assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU8::MIN.count_bits()); + /// assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU8::MAX.count_bits()); + /// } + /// ``` + fn count_bits(self) -> u32; + /// Returns the count of decimal digits in an integer. /// ### Examples /// ```rust @@ -228,8 +334,19 @@ macro_rules! impl_count_digits { ( primitive_type = $primitive_type:ty, non_zero_type = $non_zero_type:ty, + min_value_bits = $min_value_bits:expr, ) => { impl CountDigits for $primitive_type { + #[inline(always)] + /// Returns the count of bits in an integer starting with the first non-zero bit. + fn count_bits(self) -> u32 { + if self >= 0 { + 1 + self.abs_diff(0).checked_ilog2().unwrap_or_default() + } else { + $min_value_bits + } + } + #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { @@ -238,6 +355,16 @@ macro_rules! impl_count_digits { } impl CountDigits for $non_zero_type { + #[inline(always)] + /// Returns the count of bits in an integer starting with the first non-zero bit. + fn count_bits(self) -> u32 { + if self.is_positive() { + 1 + self.get().abs_diff(0).ilog2() + } else { + $min_value_bits + } + } + #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { @@ -250,6 +377,12 @@ macro_rules! impl_count_digits { non_zero_type = $non_zero_type:ty, ) => { impl CountDigits for $primitive_type { + #[inline(always)] + /// Returns the count of bits in an integer starting with the first non-zero bit. + fn count_bits(self) -> u32 { + 1 + self.checked_ilog2().unwrap_or_default() + } + #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { @@ -258,6 +391,12 @@ macro_rules! impl_count_digits { } impl CountDigits for $non_zero_type { + #[inline(always)] + /// Returns the count of bits in an integer starting with the first non-zero bit. + fn count_bits(self) -> u32 { + 1 + self.ilog2() + } + #[inline(always)] /// Returns the count of decimal digits in an integer. fn count_digits(self) -> u32 { @@ -270,50 +409,59 @@ macro_rules! impl_count_digits { impl_count_digits! { primitive_type = i8, non_zero_type = NonZeroI8, + min_value_bits = 8, } impl_count_digits! { primitive_type = i16, non_zero_type = NonZeroI16, + min_value_bits = 16, } impl_count_digits! { primitive_type = i32, non_zero_type = NonZeroI32, + min_value_bits = 32, } impl_count_digits! { primitive_type = i64, non_zero_type = NonZeroI64, + min_value_bits = 64, } impl_count_digits! { primitive_type = i128, non_zero_type = NonZeroI128, + min_value_bits = 128, } #[cfg(target_pointer_width = "64")] impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + min_value_bits = 64, } #[cfg(target_pointer_width = "32")] impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + min_value_bits = 32, } #[cfg(target_pointer_width = "16")] impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + min_value_bits = 16, } #[cfg(target_pointer_width = "8")] impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + min_value_bits = 8, } impl_count_digits! { From 746290b418bedd0c298364a69dd2208cf4a1ecab Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 04/12] Implement CountDigits::count_octal_digits() --- src/lib.rs | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index b0bfe4b86..883068b97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,6 +222,113 @@ pub trait CountDigits: Copy + Sized { /// ``` fn count_bits(self) -> u32; + /// Returns the count of octal digits in an integer starting with the first non-zero digit. + /// ### Examples + /// ```rust + /// use count_digits::CountDigits; + /// # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; + /// # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + /// + /// assert_eq!(03, i8::MIN.count_octal_digits()); + /// assert_eq!(03, i8::MAX.count_octal_digits()); + /// assert_eq!(03, NonZeroI8::MIN.count_octal_digits()); + /// assert_eq!(03, NonZeroI8::MAX.count_octal_digits()); + /// + /// assert_eq!(01, u8::MIN.count_octal_digits()); + /// assert_eq!(03, u8::MAX.count_octal_digits()); + /// assert_eq!(01, NonZeroU8::MIN.count_octal_digits()); + /// assert_eq!(03, NonZeroU8::MAX.count_octal_digits()); + /// + /// assert_eq!(06, i16::MIN.count_octal_digits()); + /// assert_eq!(05, i16::MAX.count_octal_digits()); + /// assert_eq!(06, NonZeroI16::MIN.count_octal_digits()); + /// assert_eq!(05, NonZeroI16::MAX.count_octal_digits()); + /// + /// assert_eq!(01, u16::MIN.count_octal_digits()); + /// assert_eq!(06, u16::MAX.count_octal_digits()); + /// assert_eq!(01, NonZeroU16::MIN.count_octal_digits()); + /// assert_eq!(06, NonZeroU16::MAX.count_octal_digits()); + /// + /// assert_eq!(11, i32::MIN.count_octal_digits()); + /// assert_eq!(11, i32::MAX.count_octal_digits()); + /// assert_eq!(11, NonZeroI32::MIN.count_octal_digits()); + /// assert_eq!(11, NonZeroI32::MAX.count_octal_digits()); + /// + /// assert_eq!(01, u32::MIN.count_octal_digits()); + /// assert_eq!(11, u32::MAX.count_octal_digits()); + /// assert_eq!(01, NonZeroU32::MIN.count_octal_digits()); + /// assert_eq!(11, NonZeroU32::MAX.count_octal_digits()); + /// + /// assert_eq!(22, i64::MIN.count_octal_digits()); + /// assert_eq!(21, i64::MAX.count_octal_digits()); + /// assert_eq!(22, NonZeroI64::MIN.count_octal_digits()); + /// assert_eq!(21, NonZeroI64::MAX.count_octal_digits()); + /// + /// assert_eq!(01, u64::MIN.count_octal_digits()); + /// assert_eq!(22, u64::MAX.count_octal_digits()); + /// assert_eq!(01, NonZeroU64::MIN.count_octal_digits()); + /// assert_eq!(22, NonZeroU64::MAX.count_octal_digits()); + /// + /// assert_eq!(43, i128::MIN.count_octal_digits()); + /// assert_eq!(43, i128::MAX.count_octal_digits()); + /// assert_eq!(43, NonZeroI128::MIN.count_octal_digits()); + /// assert_eq!(43, NonZeroI128::MAX.count_octal_digits()); + /// + /// assert_eq!(01, u128::MIN.count_octal_digits()); + /// assert_eq!(43, u128::MAX.count_octal_digits()); + /// assert_eq!(01, NonZeroU128::MIN.count_octal_digits()); + /// assert_eq!(43, NonZeroU128::MAX.count_octal_digits()); + /// + /// #[cfg(target_pointer_width = "64")] { + /// assert_eq!(isize::MIN.count_octal_digits(), i64::MIN.count_octal_digits()); + /// assert_eq!(isize::MAX.count_octal_digits(), i64::MAX.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI64::MIN.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI64::MAX.count_octal_digits()); + /// + /// assert_eq!(usize::MIN.count_octal_digits(), u64::MIN.count_octal_digits()); + /// assert_eq!(usize::MAX.count_octal_digits(), u64::MAX.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU64::MIN.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU64::MAX.count_octal_digits()); + /// } + /// + /// #[cfg(target_pointer_width = "32")] { + /// assert_eq!(isize::MIN.count_octal_digits(), i32::MIN.count_octal_digits()); + /// assert_eq!(isize::MAX.count_octal_digits(), i32::MAX.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI32::MIN.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI32::MAX.count_octal_digits()); + /// + /// assert_eq!(usize::MIN.count_octal_digits(), u32::MIN.count_octal_digits()); + /// assert_eq!(usize::MAX.count_octal_digits(), u32::MAX.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU32::MIN.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU32::MAX.count_octal_digits()); + /// } + /// + /// #[cfg(target_pointer_width = "16")] { + /// assert_eq!(isize::MIN.count_octal_digits(), i16::MIN.count_octal_digits()); + /// assert_eq!(isize::MAX.count_octal_digits(), i16::MAX.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI16::MIN.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI16::MAX.count_octal_digits()); + /// + /// assert_eq!(usize::MIN.count_octal_digits(), u16::MIN.count_octal_digits()); + /// assert_eq!(usize::MAX.count_octal_digits(), u16::MAX.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU16::MIN.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU16::MAX.count_octal_digits()); + /// } + /// + /// #[cfg(target_pointer_width = "8")] { + /// assert_eq!(isize::MIN.count_octal_digits(), i8::MIN.count_octal_digits()); + /// assert_eq!(isize::MAX.count_octal_digits(), i8::MAX.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI8::MIN.count_octal_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI8::MAX.count_octal_digits()); + /// + /// assert_eq!(usize::MIN.count_octal_digits(), u8::MIN.count_octal_digits()); + /// assert_eq!(usize::MAX.count_octal_digits(), u8::MAX.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU8::MIN.count_octal_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU8::MAX.count_octal_digits()); + /// } + /// ``` + fn count_octal_digits(self) -> u32; + /// Returns the count of decimal digits in an integer. /// ### Examples /// ```rust @@ -335,6 +442,7 @@ macro_rules! impl_count_digits { primitive_type = $primitive_type:ty, non_zero_type = $non_zero_type:ty, min_value_bits = $min_value_bits:expr, + min_value_octal_digits = $min_value_octal_digits:expr, ) => { impl CountDigits for $primitive_type { #[inline(always)] @@ -352,6 +460,16 @@ macro_rules! impl_count_digits { fn count_digits(self) -> u32 { 1 + self.abs_diff(0).checked_ilog10().unwrap_or_default() } + + #[inline(always)] + /// Returns the count of octal digits in an integer starting with the first non-zero digit. + fn count_octal_digits(self) -> u32 { + if self >= 0 { + 1 + self.abs_diff(0).checked_ilog(8).unwrap_or_default() + } else { + $min_value_octal_digits + } + } } impl CountDigits for $non_zero_type { @@ -370,6 +488,16 @@ macro_rules! impl_count_digits { fn count_digits(self) -> u32 { 1 + self.get().abs_diff(0).ilog10() } + + #[inline(always)] + /// Returns the count of octal digits in an integer starting with the first non-zero digit. + fn count_octal_digits(self) -> u32 { + if self.is_positive() { + 1 + self.get().abs_diff(0).ilog(8) + } else { + $min_value_octal_digits + } + } } }; ( @@ -388,6 +516,12 @@ macro_rules! impl_count_digits { fn count_digits(self) -> u32 { 1 + self.checked_ilog10().unwrap_or_default() } + + #[inline(always)] + /// Returns the count of octal digits in an integer starting with the first non-zero digit. + fn count_octal_digits(self) -> u32 { + 1 + self.checked_ilog(8).unwrap_or_default() + } } impl CountDigits for $non_zero_type { @@ -402,6 +536,12 @@ macro_rules! impl_count_digits { fn count_digits(self) -> u32 { 1 + self.ilog10() } + + #[inline(always)] + /// Returns the count of octal digits in an integer starting with the first non-zero digit. + fn count_octal_digits(self) -> u32 { + 1 + self.get().ilog(8) + } } }; } @@ -410,30 +550,35 @@ impl_count_digits! { primitive_type = i8, non_zero_type = NonZeroI8, min_value_bits = 8, + min_value_octal_digits = 3, } impl_count_digits! { primitive_type = i16, non_zero_type = NonZeroI16, min_value_bits = 16, + min_value_octal_digits = 6, } impl_count_digits! { primitive_type = i32, non_zero_type = NonZeroI32, min_value_bits = 32, + min_value_octal_digits = 11, } impl_count_digits! { primitive_type = i64, non_zero_type = NonZeroI64, min_value_bits = 64, + min_value_octal_digits = 22, } impl_count_digits! { primitive_type = i128, non_zero_type = NonZeroI128, min_value_bits = 128, + min_value_octal_digits = 43, } #[cfg(target_pointer_width = "64")] @@ -441,6 +586,7 @@ impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, min_value_bits = 64, + min_value_octal_digits = 22, } #[cfg(target_pointer_width = "32")] @@ -448,6 +594,7 @@ impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, min_value_bits = 32, + min_value_octal_digits = 11, } #[cfg(target_pointer_width = "16")] @@ -455,6 +602,7 @@ impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, min_value_bits = 16, + min_value_octal_digits = 6, } #[cfg(target_pointer_width = "8")] @@ -462,6 +610,7 @@ impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, min_value_bits = 8, + min_value_octal_digits = 3, } impl_count_digits! { From 223ba6368b05b2bebe4f3d009539c8a323b76996 Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 05/12] Implement CountDigits::count_hex_digits() --- src/lib.rs | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 883068b97..710ec099d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -435,6 +435,113 @@ pub trait CountDigits: Copy + Sized { /// } /// ``` fn count_digits(self) -> u32; + + /// Returns the count of hexadecimal digits in an integer starting with the first non-zero digit. + /// ### Examples + /// ```rust + /// use count_digits::CountDigits; + /// # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; + /// # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + /// + /// assert_eq!(02, i8::MIN.count_hex_digits()); + /// assert_eq!(02, i8::MAX.count_hex_digits()); + /// assert_eq!(02, NonZeroI8::MIN.count_hex_digits()); + /// assert_eq!(02, NonZeroI8::MAX.count_hex_digits()); + /// + /// assert_eq!(01, u8::MIN.count_hex_digits()); + /// assert_eq!(02, u8::MAX.count_hex_digits()); + /// assert_eq!(01, NonZeroU8::MIN.count_hex_digits()); + /// assert_eq!(02, NonZeroU8::MAX.count_hex_digits()); + /// + /// assert_eq!(04, i16::MIN.count_hex_digits()); + /// assert_eq!(04, i16::MAX.count_hex_digits()); + /// assert_eq!(04, NonZeroI16::MIN.count_hex_digits()); + /// assert_eq!(04, NonZeroI16::MAX.count_hex_digits()); + /// + /// assert_eq!(01, u16::MIN.count_hex_digits()); + /// assert_eq!(04, u16::MAX.count_hex_digits()); + /// assert_eq!(01, NonZeroU16::MIN.count_hex_digits()); + /// assert_eq!(04, NonZeroU16::MAX.count_hex_digits()); + /// + /// assert_eq!(08, i32::MIN.count_hex_digits()); + /// assert_eq!(08, i32::MAX.count_hex_digits()); + /// assert_eq!(08, NonZeroI32::MIN.count_hex_digits()); + /// assert_eq!(08, NonZeroI32::MAX.count_hex_digits()); + /// + /// assert_eq!(01, u32::MIN.count_hex_digits()); + /// assert_eq!(08, u32::MAX.count_hex_digits()); + /// assert_eq!(01, NonZeroU32::MIN.count_hex_digits()); + /// assert_eq!(08, NonZeroU32::MAX.count_hex_digits()); + /// + /// assert_eq!(16, i64::MIN.count_hex_digits()); + /// assert_eq!(16, i64::MAX.count_hex_digits()); + /// assert_eq!(16, NonZeroI64::MIN.count_hex_digits()); + /// assert_eq!(16, NonZeroI64::MAX.count_hex_digits()); + /// + /// assert_eq!(01, u64::MIN.count_hex_digits()); + /// assert_eq!(16, u64::MAX.count_hex_digits()); + /// assert_eq!(01, NonZeroU64::MIN.count_hex_digits()); + /// assert_eq!(16, NonZeroU64::MAX.count_hex_digits()); + /// + /// assert_eq!(32, i128::MIN.count_hex_digits()); + /// assert_eq!(32, i128::MAX.count_hex_digits()); + /// assert_eq!(32, NonZeroI128::MIN.count_hex_digits()); + /// assert_eq!(32, NonZeroI128::MAX.count_hex_digits()); + /// + /// assert_eq!(01, u128::MIN.count_hex_digits()); + /// assert_eq!(32, u128::MAX.count_hex_digits()); + /// assert_eq!(01, NonZeroU128::MIN.count_hex_digits()); + /// assert_eq!(32, NonZeroU128::MAX.count_hex_digits()); + /// + /// #[cfg(target_pointer_width = "64")] { + /// assert_eq!(isize::MIN.count_hex_digits(), i64::MIN.count_hex_digits()); + /// assert_eq!(isize::MAX.count_hex_digits(), i64::MAX.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI64::MIN.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI64::MAX.count_hex_digits()); + /// + /// assert_eq!(usize::MIN.count_hex_digits(), u64::MIN.count_hex_digits()); + /// assert_eq!(usize::MAX.count_hex_digits(), u64::MAX.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU64::MIN.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU64::MAX.count_hex_digits()); + /// } + /// + /// #[cfg(target_pointer_width = "32")] { + /// assert_eq!(isize::MIN.count_hex_digits(), i32::MIN.count_hex_digits()); + /// assert_eq!(isize::MAX.count_hex_digits(), i32::MAX.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI32::MIN.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI32::MAX.count_hex_digits()); + /// + /// assert_eq!(usize::MIN.count_hex_digits(), u32::MIN.count_hex_digits()); + /// assert_eq!(usize::MAX.count_hex_digits(), u32::MAX.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU32::MIN.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU32::MAX.count_hex_digits()); + /// } + /// + /// #[cfg(target_pointer_width = "16")] { + /// assert_eq!(isize::MIN.count_hex_digits(), i16::MIN.count_hex_digits()); + /// assert_eq!(isize::MAX.count_hex_digits(), i16::MAX.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI16::MIN.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI16::MAX.count_hex_digits()); + /// + /// assert_eq!(usize::MIN.count_hex_digits(), u16::MIN.count_hex_digits()); + /// assert_eq!(usize::MAX.count_hex_digits(), u16::MAX.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU16::MIN.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU16::MAX.count_hex_digits()); + /// } + /// + /// #[cfg(target_pointer_width = "8")] { + /// assert_eq!(isize::MIN.count_hex_digits(), i8::MIN.count_hex_digits()); + /// assert_eq!(isize::MAX.count_hex_digits(), i8::MAX.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI8::MIN.count_hex_digits()); + /// assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI8::MAX.count_hex_digits()); + /// + /// assert_eq!(usize::MIN.count_hex_digits(), u8::MIN.count_hex_digits()); + /// assert_eq!(usize::MAX.count_hex_digits(), u8::MAX.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU8::MIN.count_hex_digits()); + /// assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU8::MAX.count_hex_digits()); + /// } + /// ``` + fn count_hex_digits(self) -> u32; } macro_rules! impl_count_digits { @@ -443,6 +550,7 @@ macro_rules! impl_count_digits { non_zero_type = $non_zero_type:ty, min_value_bits = $min_value_bits:expr, min_value_octal_digits = $min_value_octal_digits:expr, + min_value_hex_digits = $min_value_hex_digits:expr $(,)? ) => { impl CountDigits for $primitive_type { #[inline(always)] @@ -470,6 +578,16 @@ macro_rules! impl_count_digits { $min_value_octal_digits } } + + #[inline(always)] + /// Returns the count of hexadecimal digits in an integer starting with the first non-zero digit. + fn count_hex_digits(self) -> u32 { + if self >= 0 { + 1 + self.abs_diff(0).checked_ilog(16).unwrap_or_default() + } else { + $min_value_hex_digits + } + } } impl CountDigits for $non_zero_type { @@ -498,6 +616,16 @@ macro_rules! impl_count_digits { $min_value_octal_digits } } + + #[inline(always)] + /// Returns the count of hexadecimal digits in an integer starting with the first non-zero digit. + fn count_hex_digits(self) -> u32 { + if self.is_positive() { + 1 + self.get().abs_diff(0).ilog(16) + } else { + $min_value_hex_digits + } + } } }; ( @@ -522,6 +650,12 @@ macro_rules! impl_count_digits { fn count_octal_digits(self) -> u32 { 1 + self.checked_ilog(8).unwrap_or_default() } + + #[inline(always)] + /// Returns the count of hexadecimal digits in an integer starting with the first non-zero digit. + fn count_hex_digits(self) -> u32 { + 1 + self.checked_ilog(16).unwrap_or_default() + } } impl CountDigits for $non_zero_type { @@ -542,6 +676,12 @@ macro_rules! impl_count_digits { fn count_octal_digits(self) -> u32 { 1 + self.get().ilog(8) } + + #[inline(always)] + /// Returns the count of hexadecimal digits in an integer starting with the first non-zero digit. + fn count_hex_digits(self) -> u32 { + 1 + self.get().ilog(16) + } } }; } @@ -551,6 +691,7 @@ impl_count_digits! { non_zero_type = NonZeroI8, min_value_bits = 8, min_value_octal_digits = 3, + min_value_hex_digits = 2, } impl_count_digits! { @@ -558,6 +699,7 @@ impl_count_digits! { non_zero_type = NonZeroI16, min_value_bits = 16, min_value_octal_digits = 6, + min_value_hex_digits = 4, } impl_count_digits! { @@ -565,6 +707,7 @@ impl_count_digits! { non_zero_type = NonZeroI32, min_value_bits = 32, min_value_octal_digits = 11, + min_value_hex_digits = 8, } impl_count_digits! { @@ -572,6 +715,7 @@ impl_count_digits! { non_zero_type = NonZeroI64, min_value_bits = 64, min_value_octal_digits = 22, + min_value_hex_digits = 16, } impl_count_digits! { @@ -579,6 +723,7 @@ impl_count_digits! { non_zero_type = NonZeroI128, min_value_bits = 128, min_value_octal_digits = 43, + min_value_hex_digits = 32, } #[cfg(target_pointer_width = "64")] @@ -587,6 +732,7 @@ impl_count_digits! { non_zero_type = NonZeroIsize, min_value_bits = 64, min_value_octal_digits = 22, + min_value_hex_digits = 16, } #[cfg(target_pointer_width = "32")] @@ -595,6 +741,7 @@ impl_count_digits! { non_zero_type = NonZeroIsize, min_value_bits = 32, min_value_octal_digits = 11, + min_value_hex_digits = 8, } #[cfg(target_pointer_width = "16")] @@ -603,6 +750,7 @@ impl_count_digits! { non_zero_type = NonZeroIsize, min_value_bits = 16, min_value_octal_digits = 6, + min_value_hex_digits = 4, } #[cfg(target_pointer_width = "8")] @@ -611,6 +759,7 @@ impl_count_digits! { non_zero_type = NonZeroIsize, min_value_bits = 8, min_value_octal_digits = 3, + min_value_hex_digits = 2, } impl_count_digits! { From 5e0bdce68f8b575cfa9fedc2bc503d68739b7320 Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 06/12] Implement CountDigits::count_digits_radix() --- src/lib.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 710ec099d..9388d5c52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(clippy::zero_prefixed_literal)] //! # CountDigits //! //! A trait to count the decimal digits of an integer. @@ -116,6 +117,10 @@ use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZ /// Count the decimal digits of an integer. pub trait CountDigits: Copy + Sized { + /// The type of integer that should be passed in to the + /// [count_digits_radix()](CountDigits::count_digits_radix) function. + type Radix; + /// Returns the count of bits in an integer starting with the first non-zero bit. /// ```rust /// use count_digits::CountDigits; @@ -542,17 +547,34 @@ pub trait CountDigits: Copy + Sized { /// } /// ``` fn count_hex_digits(self) -> u32; + + /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix). + /// ### Examples + /// ```rust + /// use count_digits::CountDigits; + /// + /// for n in 0..1_000_000 { + /// assert_eq!(n.count_digits_radix(02_u32), n.count_bits()); + /// assert_eq!(n.count_digits_radix(08_u32), n.count_octal_digits()); + /// assert_eq!(n.count_digits_radix(10_u32), n.count_digits()); + /// assert_eq!(n.count_digits_radix(16_u32), n.count_hex_digits()); + /// } + /// ``` + fn count_digits_radix(self, radix: Self::Radix) -> u32; } macro_rules! impl_count_digits { ( primitive_type = $primitive_type:ty, non_zero_type = $non_zero_type:ty, + radix_type = $radix_type:ty, min_value_bits = $min_value_bits:expr, min_value_octal_digits = $min_value_octal_digits:expr, min_value_hex_digits = $min_value_hex_digits:expr $(,)? ) => { impl CountDigits for $primitive_type { + type Radix = $radix_type; + #[inline(always)] /// Returns the count of bits in an integer starting with the first non-zero bit. fn count_bits(self) -> u32 { @@ -588,9 +610,32 @@ macro_rules! impl_count_digits { $min_value_hex_digits } } + + #[inline(always)] + /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix). + fn count_digits_radix(self, radix: Self::Radix) -> u32 { + match radix { + 02 => self.count_bits(), + 08 => self.count_octal_digits(), + 10 => self.count_digits(), + 16 => self.count_hex_digits(), + __ => { + if self >= 0 { + 1 + self.abs_diff(0).checked_ilog(radix).unwrap_or_default() + } else { + 1 + <$primitive_type>::MIN + .abs_diff(0) + .checked_ilog(radix) + .unwrap_or_default() + } + } + } + } } impl CountDigits for $non_zero_type { + type Radix = $radix_type; + #[inline(always)] /// Returns the count of bits in an integer starting with the first non-zero bit. fn count_bits(self) -> u32 { @@ -626,6 +671,24 @@ macro_rules! impl_count_digits { $min_value_hex_digits } } + + #[inline(always)] + /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix). + fn count_digits_radix(self, radix: Self::Radix) -> u32 { + match radix { + 02 => self.count_bits(), + 08 => self.count_octal_digits(), + 10 => self.count_digits(), + 16 => self.count_hex_digits(), + __ => { + if self.is_positive() { + 1 + self.get().abs_diff(0).ilog(radix) + } else { + 1 + <$non_zero_type>::MIN.get().abs_diff(0).ilog(radix) + } + } + } + } } }; ( @@ -633,6 +696,8 @@ macro_rules! impl_count_digits { non_zero_type = $non_zero_type:ty, ) => { impl CountDigits for $primitive_type { + type Radix = $primitive_type; + #[inline(always)] /// Returns the count of bits in an integer starting with the first non-zero bit. fn count_bits(self) -> u32 { @@ -656,9 +721,23 @@ macro_rules! impl_count_digits { fn count_hex_digits(self) -> u32 { 1 + self.checked_ilog(16).unwrap_or_default() } + + #[inline(always)] + /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix). + fn count_digits_radix(self, radix: Self::Radix) -> u32 { + match radix { + 02 => self.count_bits(), + 08 => self.count_octal_digits(), + 10 => self.count_digits(), + 16 => self.count_hex_digits(), + __ => 1 + self.checked_ilog(radix).unwrap_or_default(), + } + } } impl CountDigits for $non_zero_type { + type Radix = $primitive_type; + #[inline(always)] /// Returns the count of bits in an integer starting with the first non-zero bit. fn count_bits(self) -> u32 { @@ -682,6 +761,18 @@ macro_rules! impl_count_digits { fn count_hex_digits(self) -> u32 { 1 + self.get().ilog(16) } + + #[inline(always)] + /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix). + fn count_digits_radix(self, radix: Self::Radix) -> u32 { + match radix { + 02 => self.count_bits(), + 08 => self.count_octal_digits(), + 10 => self.count_digits(), + 16 => self.count_hex_digits(), + _ => 1 + self.get().ilog(radix), + } + } } }; } @@ -689,6 +780,7 @@ macro_rules! impl_count_digits { impl_count_digits! { primitive_type = i8, non_zero_type = NonZeroI8, + radix_type = u8, min_value_bits = 8, min_value_octal_digits = 3, min_value_hex_digits = 2, @@ -697,6 +789,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = i16, non_zero_type = NonZeroI16, + radix_type = u16, min_value_bits = 16, min_value_octal_digits = 6, min_value_hex_digits = 4, @@ -705,6 +798,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = i32, non_zero_type = NonZeroI32, + radix_type = u32, min_value_bits = 32, min_value_octal_digits = 11, min_value_hex_digits = 8, @@ -713,6 +807,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = i64, non_zero_type = NonZeroI64, + radix_type = u64, min_value_bits = 64, min_value_octal_digits = 22, min_value_hex_digits = 16, @@ -721,6 +816,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = i128, non_zero_type = NonZeroI128, + radix_type = u128, min_value_bits = 128, min_value_octal_digits = 43, min_value_hex_digits = 32, @@ -730,6 +826,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + radix_type = usize, min_value_bits = 64, min_value_octal_digits = 22, min_value_hex_digits = 16, @@ -739,6 +836,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + radix_type = usize, min_value_bits = 32, min_value_octal_digits = 11, min_value_hex_digits = 8, @@ -748,6 +846,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + radix_type = usize, min_value_bits = 16, min_value_octal_digits = 6, min_value_hex_digits = 4, @@ -757,6 +856,7 @@ impl_count_digits! { impl_count_digits! { primitive_type = isize, non_zero_type = NonZeroIsize, + radix_type = usize, min_value_bits = 8, min_value_octal_digits = 3, min_value_hex_digits = 2, From 31b5d303ccf0f9f98a80745c2a469bd8ba76453d Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 07/12] Refactor min_and_max tests --- src/lib.rs | 199 ++++++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 95 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9388d5c52..58a0b6b74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![no_std] +#![cfg_attr(not(test), no_std)] #![allow(clippy::zero_prefixed_literal)] //! # CountDigits //! @@ -897,113 +897,122 @@ mod count_digits { use super::*; use paste::paste; - trait MinAndMax { - const MAX_VALUE_DIGITS: u32; - const MAX_VALUE: Self; - - const MIN_VALUE_DIGITS: u32; - const MIN_VALUE: Self; + macro_rules! binary_string_count { + ($n:expr) => { + format!("{:b}", $n).len() as u32 + }; } - macro_rules! impl_min_and_max { - ($type:ty, $min_digits:expr, $max_digits:expr) => { - impl MinAndMax for $type { - const MAX_VALUE_DIGITS: u32 = $max_digits; - const MAX_VALUE: Self = Self::MAX; - - const MIN_VALUE_DIGITS: u32 = $min_digits; - const MIN_VALUE: Self = Self::MIN; - } + macro_rules! octal_string_count { + ($n:expr) => { + format!("{:o}", $n).len() as u32 }; } - impl_min_and_max!(i8, 3, 3); - impl_min_and_max!(NonZeroI8, 3, 3); - - impl_min_and_max!(i16, 5, 5); - impl_min_and_max!(NonZeroI16, 5, 5); - - impl_min_and_max!(i32, 10, 10); - impl_min_and_max!(NonZeroI32, 10, 10); - - impl_min_and_max!(i64, 19, 19); - impl_min_and_max!(NonZeroI64, 19, 19); - - impl_min_and_max!(i128, 39, 39); - impl_min_and_max!(NonZeroI128, 39, 39); - - impl_min_and_max!(u8, 1, 3); - impl_min_and_max!(NonZeroU8, 1, 3); - - impl_min_and_max!(u16, 1, 5); - impl_min_and_max!(NonZeroU16, 1, 5); - - impl_min_and_max!(u32, 1, 10); - impl_min_and_max!(NonZeroU32, 1, 10); - - impl_min_and_max!(u64, 1, 20); - impl_min_and_max!(NonZeroU64, 1, 20); - - impl_min_and_max!(u128, 1, 39); - impl_min_and_max!(NonZeroU128, 1, 39); - - #[cfg(target_pointer_width = "64")] - impl_min_and_max!(isize, i64::MIN_VALUE_DIGITS, i64::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "64")] - impl_min_and_max!(NonZeroIsize, i64::MIN_VALUE_DIGITS, i64::MAX_VALUE_DIGITS); - - #[cfg(target_pointer_width = "32")] - impl_min_and_max!(isize, i32::MIN_VALUE_DIGITS, i32::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "32")] - impl_min_and_max!(NonZeroIsize, i32::MIN_VALUE_DIGITS, i32::MAX_VALUE_DIGITS); - - #[cfg(target_pointer_width = "16")] - impl_min_and_max!(isize, i16::MIN_VALUE_DIGITS, i16::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "16")] - impl_min_and_max!(NonZeroIsize, i16::MIN_VALUE_DIGITS, i16::MAX_VALUE_DIGITS); - - #[cfg(target_pointer_width = "8")] - impl_min_and_max!(isize, i8::MIN_VALUE_DIGITS, i8::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "8")] - impl_min_and_max!(NonZeroIsize, i8::MIN_VALUE_DIGITS, i8::MAX_VALUE_DIGITS); - - #[cfg(target_pointer_width = "64")] - impl_min_and_max!(usize, u64::MIN_VALUE_DIGITS, u64::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "64")] - impl_min_and_max!(NonZeroUsize, u64::MIN_VALUE_DIGITS, u64::MAX_VALUE_DIGITS); - - #[cfg(target_pointer_width = "32")] - impl_min_and_max!(usize, u32::MIN_VALUE_DIGITS, u32::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "32")] - impl_min_and_max!(NonZeroUsize, u32::MIN_VALUE_DIGITS, u32::MAX_VALUE_DIGITS); + macro_rules! decimal_string_count { + ($n:expr) => {{ + let string = format!("{}", $n); + string.strip_prefix('-').unwrap_or(&string).len() as u32 + }}; + } - #[cfg(target_pointer_width = "16")] - impl_min_and_max!(usize, u16::MIN_VALUE_DIGITS, u16::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "16")] - impl_min_and_max!(NonZeroUsize, u16::MIN_VALUE_DIGITS, u16::MAX_VALUE_DIGITS); + macro_rules! hex_string_count { + ($n:expr) => { + format!("{:X}", $n).len() as u32 + }; + } - #[cfg(target_pointer_width = "8")] - impl_min_and_max!(usize, u8::MIN_VALUE_DIGITS, u8::MAX_VALUE_DIGITS); - #[cfg(target_pointer_width = "8")] - impl_min_and_max!(NonZeroUsize, u8::MIN_VALUE_DIGITS, u8::MAX_VALUE_DIGITS); + macro_rules! assert_min_and_max { + ($type:ty) => { + assert_eq!( + <$type>::MIN.count_bits(), + binary_string_count!(<$type>::MIN) + ); + assert_eq!( + <$type>::MIN.count_digits_radix(2), + binary_string_count!(<$type>::MIN) + ); + + assert_eq!( + <$type>::MAX.count_bits(), + binary_string_count!(<$type>::MAX) + ); + assert_eq!( + <$type>::MAX.count_digits_radix(2), + binary_string_count!(<$type>::MAX) + ); + + assert_eq!( + <$type>::MIN.count_octal_digits(), + octal_string_count!(<$type>::MIN), + ); + assert_eq!( + <$type>::MIN.count_digits_radix(8), + octal_string_count!(<$type>::MIN), + ); + + assert_eq!( + <$type>::MAX.count_octal_digits(), + octal_string_count!(<$type>::MAX), + ); + assert_eq!( + <$type>::MAX.count_digits_radix(8), + octal_string_count!(<$type>::MAX), + ); + + assert_eq!( + <$type>::MIN.count_digits(), + decimal_string_count!(<$type>::MIN) + ); + assert_eq!( + <$type>::MIN.count_digits_radix(10), + decimal_string_count!(<$type>::MIN), + ); + + assert_eq!( + <$type>::MAX.count_digits(), + decimal_string_count!(<$type>::MAX) + ); + assert_eq!( + <$type>::MAX.count_digits_radix(10), + decimal_string_count!(<$type>::MAX), + ); + + assert_eq!( + <$type>::MIN.count_hex_digits(), + hex_string_count!(<$type>::MIN), + ); + assert_eq!( + <$type>::MIN.count_digits_radix(16), + hex_string_count!(<$type>::MIN), + ); + + assert_eq!( + <$type>::MAX.count_hex_digits(), + hex_string_count!(<$type>::MAX), + ); + assert_eq!( + <$type>::MAX.count_digits_radix(16), + hex_string_count!(<$type>::MAX), + ); + }; + } macro_rules! min_and_max { ($type:ty, $non_zero_type:ty) => { paste! { #[test] fn []() { - assert_eq!($type::MIN_VALUE.count_digits(), $type::MIN_VALUE_DIGITS,); - assert_eq!($type::MAX_VALUE.count_digits(), $type::MAX_VALUE_DIGITS,); + assert_min_and_max!($type); } #[test] #[allow(non_snake_case)] fn []() { - assert_eq!($non_zero_type::MIN_VALUE.count_digits(), $non_zero_type::MIN_VALUE_DIGITS,); - assert_eq!($non_zero_type::MAX_VALUE.count_digits(), $non_zero_type::MAX_VALUE_DIGITS,); + assert_min_and_max!($type); } } - } + }; } macro_rules! min_to_max_or_one_million { @@ -1107,13 +1116,6 @@ mod count_digits { }; } - add_test!(min_and_max, u8, NonZeroU8); - add_test!(min_and_max, u16, NonZeroU16); - add_test!(min_and_max, u32, NonZeroU32); - add_test!(min_and_max, u64, NonZeroU64); - add_test!(min_and_max, u128, NonZeroU128); - add_test!(min_and_max, usize, NonZeroUsize); - add_test!(min_and_max, i8, NonZeroI8); add_test!(min_and_max, i16, NonZeroI16); add_test!(min_and_max, i32, NonZeroI32); @@ -1121,6 +1123,13 @@ mod count_digits { add_test!(min_and_max, i128, NonZeroI128); add_test!(min_and_max, isize, NonZeroIsize); + add_test!(min_and_max, u8, NonZeroU8); + add_test!(min_and_max, u16, NonZeroU16); + add_test!(min_and_max, u32, NonZeroU32); + add_test!(min_and_max, u64, NonZeroU64); + add_test!(min_and_max, u128, NonZeroU128); + add_test!(min_and_max, usize, NonZeroUsize); + add_test!(min_to_max_or_one_million, u8, NonZeroU8); add_test!(min_to_max_or_one_million, u16, NonZeroU16); add_test!(min_to_max_or_one_million, u32, NonZeroU32); From 3953d6276ed807ae86473f4ef55d59480cb4387c Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 08/12] Refactor iteration tests --- src/lib.rs | 84 +++++++++++++++++++++++++----------------------------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 58a0b6b74..6876c403b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -998,6 +998,41 @@ mod count_digits { }; } + macro_rules! assert_representations { + ($n:expr) => { + assert_eq!($n.count_bits(), binary_string_count!($n)); + assert_eq!($n.count_digits_radix(2), binary_string_count!($n)); + + assert_eq!($n.count_octal_digits(), octal_string_count!($n)); + assert_eq!($n.count_digits_radix(8), octal_string_count!($n)); + + assert_eq!($n.count_digits(), decimal_string_count!($n)); + assert_eq!($n.count_digits_radix(10), decimal_string_count!($n)); + + assert_eq!($n.count_hex_digits(), hex_string_count!($n)); + assert_eq!($n.count_digits_radix(16), hex_string_count!($n)); + + assert!([ + $n.count_digits_radix(2), + $n.count_digits_radix(3), + $n.count_digits_radix(4), + $n.count_digits_radix(5), + $n.count_digits_radix(6), + $n.count_digits_radix(7), + $n.count_digits_radix(8), + $n.count_digits_radix(9), + $n.count_digits_radix(11), + $n.count_digits_radix(12), + $n.count_digits_radix(13), + $n.count_digits_radix(14), + $n.count_digits_radix(15), + $n.count_digits_radix(16), + ] + .windows(2) + .all(|window| window[0] >= window[1])); + }; + } + macro_rules! min_and_max { ($type:ty, $non_zero_type:ty) => { paste! { @@ -1023,14 +1058,7 @@ mod count_digits { fn []() { let max = if ($type::MAX as u128) < 1_000_000 { $type::MAX } else { 1_000_000 }; for n in $type::MIN..=max { - let i128 = n as i128; - if i128 < 10 { assert_eq!(n.count_digits(), 1, "Expect count of 1 for {n}") } - else if i128 < 100 { assert_eq!(n.count_digits(), 2, "Expect count of 2 for {n}") } - else if i128 < 1_000 { assert_eq!(n.count_digits(), 3, "Expect count of 3 for {n}") } - else if i128 < 10_000 { assert_eq!(n.count_digits(), 4, "Expect count of 4 for {n}") } - else if i128 < 100_000 { assert_eq!(n.count_digits(), 5, "Expect count of 5 for {n}") } - else if i128 < 1_000_000 { assert_eq!(n.count_digits(), 6, "Expect count of 6 for {n}") } - else if i128 == 1_000_000 { assert_eq!(n.count_digits(), 7, "Expect count of 7 for {n}") } + assert_representations!(n); } } @@ -1040,15 +1068,7 @@ mod count_digits { fn []() { let max = if ($type::MAX as u128) < 1_000_000 { $type::MAX } else { 1_000_000 }; for n in $non_zero_type::MIN.get()..=max { - let i128 = n as u128; - let n = $non_zero_type::new(n).unwrap(); - if i128 < 10 { assert_eq!(n.count_digits(), 1, "Expect count of 1 for {n}") } - else if i128 < 100 { assert_eq!(n.count_digits(), 2, "Expect count of 2 for {n}") } - else if i128 < 1_000 { assert_eq!(n.count_digits(), 3, "Expect count of 3 for {n}") } - else if i128 < 10_000 { assert_eq!(n.count_digits(), 4, "Expect count of 4 for {n}") } - else if i128 < 100_000 { assert_eq!(n.count_digits(), 5, "Expect count of 5 for {n}") } - else if i128 < 1_000_000 { assert_eq!(n.count_digits(), 6, "Expect count of 6 for {n}") } - else if i128 == 1_000_000 { assert_eq!(n.count_digits(), 7, "Expect count of 7 for {n}") } + assert_representations!(n); } } } @@ -1064,20 +1084,7 @@ mod count_digits { let max = if ($type::MAX as u128) < 1_000_000 { $type::MAX } else { 1_000_000 }; let min = if ($type::MIN as i128) > -1_000_000 { $type::MIN } else { -1_000_000 }; for n in min..=max { - let i128 = n as i128; - if i128 == -1_000_000 { assert_eq!(n.count_digits(), 7, "Expect count of 7 for {n}") } - else if i128 < -99_999 { assert_eq!(n.count_digits(), 6, "Expect count of 6 for {n}") } - else if i128 < -9_999 { assert_eq!(n.count_digits(), 5, "Expect count of 5 for {n}") } - else if i128 < -999 { assert_eq!(n.count_digits(), 4, "Expect count of 4 for {n}") } - else if i128 < -99 { assert_eq!(n.count_digits(), 3, "Expect count of 3 for {n}") } - else if i128 < -9 { assert_eq!(n.count_digits(), 2, "Expect count of 2 for {n}") } - else if i128 < 10 { assert_eq!(n.count_digits(), 1, "Expect count of 1 for {n}") } - else if i128 < 100 { assert_eq!(n.count_digits(), 2, "Expect count of 2 for {n}") } - else if i128 < 1_000 { assert_eq!(n.count_digits(), 3, "Expect count of 3 for {n}") } - else if i128 < 10_000 { assert_eq!(n.count_digits(), 4, "Expect count of 4 for {n}") } - else if i128 < 100_000 { assert_eq!(n.count_digits(), 5, "Expect count of 5 for {n}") } - else if i128 < 1_000_000 { assert_eq!(n.count_digits(), 6, "Expect count of 6 for {n}") } - else if i128 == 1_000_000 { assert_eq!(n.count_digits(), 7, "Expect count of 7 for {n}") } + assert_representations!(n); } } @@ -1089,21 +1096,8 @@ mod count_digits { let min = if ($type::MIN as i128) > -1_000_000 { $type::MIN } else { -1_000_000 }; for n in min..=max { if n == 0 { continue; } - let i128 = n as i128; let n = $non_zero_type::new(n).unwrap(); - if i128 == -1_000_000 { assert_eq!(n.count_digits(), 7, "Expect count of 6 for {n}") } - else if i128 < -99_999 { assert_eq!(n.count_digits(), 6, "Expect count of 6 for {n}") } - else if i128 < -9_999 { assert_eq!(n.count_digits(), 5, "Expect count of 5 for {n}") } - else if i128 < -999 { assert_eq!(n.count_digits(), 4, "Expect count of 4 for {n}") } - else if i128 < -99 { assert_eq!(n.count_digits(), 3, "Expect count of 3 for {n}") } - else if i128 < -9 { assert_eq!(n.count_digits(), 2, "Expect count of 2 for {n}") } - else if i128 < 10 { assert_eq!(n.count_digits(), 1, "Expect count of 1 for {n}") } - else if i128 < 100 { assert_eq!(n.count_digits(), 2, "Expect count of 2 for {n}") } - else if i128 < 1_000 { assert_eq!(n.count_digits(), 3, "Expect count of 3 for {n}") } - else if i128 < 10_000 { assert_eq!(n.count_digits(), 4, "Expect count of 4 for {n}") } - else if i128 < 100_000 { assert_eq!(n.count_digits(), 5, "Expect count of 5 for {n}") } - else if i128 < 1_000_000 { assert_eq!(n.count_digits(), 6, "Expect count of 6 for {n}") } - else if i128 == 1_000_000 { assert_eq!(n.count_digits(), 7, "Expect count of 7 for {n}") } + assert_representations!(n); } } } From ec8b9b8af072e1447ca7f1c9f4ed191acce172cc Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 09/12] Update top-level documentation --- src/lib.rs | 158 ++++++++++++++++++++++------------------------------- 1 file changed, 65 insertions(+), 93 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6876c403b..eee9f769f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,120 +2,87 @@ #![allow(clippy::zero_prefixed_literal)] //! # CountDigits //! -//! A trait to count the decimal digits of an integer. +//! A [no_std](https://docs.rust-embedded.org/book/intro/no-std.html) trait to count +//! the digits of an integer in various number bases. //! -//! [CountDigits] is compatible with all the primitive integer types, -//! and all non-zero integer types. +//! Compatible with all primitive integer types and all non-zero integer types. //! -//! ### Examples +//! #### Examples //! ```rust //! use count_digits::CountDigits; -//! # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; -//! # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; +//! use core::num::NonZeroIsize; //! -//! assert_eq!(03, i8::MIN.count_digits()); -//! assert_eq!(03, i8::MAX.count_digits()); -//! assert_eq!(03, NonZeroI8::MIN.count_digits()); -//! assert_eq!(03, NonZeroI8::MAX.count_digits()); +//! assert_eq!(16, 0b1111000000001101.count_bits()); +//! assert_eq!(16, 0b1111000000001101.count_digits_radix(2_u32)); //! -//! assert_eq!(01, u8::MIN.count_digits()); -//! assert_eq!(03, u8::MAX.count_digits()); -//! assert_eq!(01, NonZeroU8::MIN.count_digits()); -//! assert_eq!(03, NonZeroU8::MAX.count_digits()); +//! assert_eq!(06, 0o170015.count_octal_digits()); +//! assert_eq!(06, 0o170015.count_digits_radix(8_u32)); //! -//! assert_eq!(05, i16::MIN.count_digits()); -//! assert_eq!(05, i16::MAX.count_digits()); -//! assert_eq!(05, NonZeroI16::MIN.count_digits()); -//! assert_eq!(05, NonZeroI16::MAX.count_digits()); +//! assert_eq!(05, 61453.count_digits()); +//! assert_eq!(05, 61453.count_digits_radix(10_u32)); //! -//! assert_eq!(01, u16::MIN.count_digits()); -//! assert_eq!(05, u16::MAX.count_digits()); -//! assert_eq!(01, NonZeroU16::MIN.count_digits()); -//! assert_eq!(05, NonZeroU16::MAX.count_digits()); +//! assert_eq!(04, 0xF00D.count_hex_digits()); +//! assert_eq!(04, 0xF00D.count_digits_radix(16_u32)); //! -//! assert_eq!(10, i32::MIN.count_digits()); -//! assert_eq!(10, i32::MAX.count_digits()); -//! assert_eq!(10, NonZeroI32::MIN.count_digits()); -//! assert_eq!(10, NonZeroI32::MAX.count_digits()); -//! -//! assert_eq!(01, u32::MIN.count_digits()); -//! assert_eq!(10, u32::MAX.count_digits()); -//! assert_eq!(01, NonZeroU32::MIN.count_digits()); -//! assert_eq!(10, NonZeroU32::MAX.count_digits()); -//! -//! assert_eq!(19, i64::MIN.count_digits()); -//! assert_eq!(19, i64::MAX.count_digits()); -//! assert_eq!(19, NonZeroI64::MIN.count_digits()); -//! assert_eq!(19, NonZeroI64::MAX.count_digits()); -//! -//! assert_eq!(01, u64::MIN.count_digits()); -//! assert_eq!(20, u64::MAX.count_digits()); -//! assert_eq!(01, NonZeroU64::MIN.count_digits()); -//! assert_eq!(20, NonZeroU64::MAX.count_digits()); -//! -//! assert_eq!(39, i128::MIN.count_digits()); -//! assert_eq!(39, i128::MAX.count_digits()); -//! assert_eq!(39, NonZeroI128::MIN.count_digits()); -//! assert_eq!(39, NonZeroI128::MAX.count_digits()); -//! -//! assert_eq!(01, u128::MIN.count_digits()); -//! assert_eq!(39, u128::MAX.count_digits()); -//! assert_eq!(01, NonZeroU128::MIN.count_digits()); -//! assert_eq!(39, NonZeroU128::MAX.count_digits()); -//! -//! #[cfg(target_pointer_width = "64")] { -//! assert_eq!(isize::MIN.count_digits(), i64::MIN.count_digits()); -//! assert_eq!(isize::MAX.count_digits(), i64::MAX.count_digits()); -//! assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI64::MIN.count_digits()); -//! assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI64::MAX.count_digits()); +//! assert_eq!( +//! 0xF00D_isize.count_digits(), +//! NonZeroIsize::new(0xF00D).unwrap().count_digits(), +//! ); +//! ``` //! -//! assert_eq!(usize::MIN.count_digits(), u64::MIN.count_digits()); -//! assert_eq!(usize::MAX.count_digits(), u64::MAX.count_digits()); -//! assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU64::MIN.count_digits()); -//! assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU64::MAX.count_digits()); -//! } +//! ##### Note //! -//! #[cfg(target_pointer_width = "32")] { -//! assert_eq!(isize::MIN.count_digits(), i32::MIN.count_digits()); -//! assert_eq!(isize::MAX.count_digits(), i32::MAX.count_digits()); -//! assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI32::MIN.count_digits()); -//! assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI32::MAX.count_digits()); +//! Be mindful with negative signed integers in non-decimal number bases. //! -//! assert_eq!(usize::MIN.count_digits(), u32::MIN.count_digits()); -//! assert_eq!(usize::MAX.count_digits(), u32::MAX.count_digits()); -//! assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU32::MIN.count_digits()); -//! assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU32::MAX.count_digits()); -//! } +//! Since negative decimal numbers are represented with a negative sign, +//! the decimal digit count of a negative number will be equal to its +//! positive counterpart. //! -//! #[cfg(target_pointer_width = "16")] { -//! assert_eq!(isize::MIN.count_digits(), i16::MIN.count_digits()); -//! assert_eq!(isize::MAX.count_digits(), i16::MAX.count_digits()); -//! assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI16::MIN.count_digits()); -//! assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI16::MAX.count_digits()); +//! ```rust +//! # use count_digits::CountDigits; +//! assert_eq!( +//! 0xF00D_i32.count_digits(), +//! 0xF00D_i32.wrapping_neg().count_digits(), +//! ); +//! ```` //! -//! assert_eq!(usize::MIN.count_digits(), u16::MIN.count_digits()); -//! assert_eq!(usize::MAX.count_digits(), u16::MAX.count_digits()); -//! assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU16::MIN.count_digits()); -//! assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU16::MAX.count_digits()); -//! } +//! However, a negative number using a different radix will not have the +//! same count of digits as its positive counterpart. //! -//! #[cfg(target_pointer_width = "8")] { -//! assert_eq!(isize::MIN.count_digits(), i8::MIN.count_digits()); -//! assert_eq!(isize::MAX.count_digits(), i8::MAX.count_digits()); -//! assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI8::MIN.count_digits()); -//! assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI8::MAX.count_digits()); +//! ```rust +//! # use count_digits::CountDigits; +//! assert_ne!( +//! 0xBAD_i32.count_bits(), +//! 0xBAD_i32.wrapping_neg().count_bits(), +//! ); +//! assert_ne!( +//! 0xBAD_i32.count_octal_digits(), +//! 0xBAD_i32.wrapping_neg().count_octal_digits(), +//! ); +//! assert_ne!( +//! 0xBAD_i32.count_hex_digits(), +//! 0xBAD_i32.wrapping_neg().count_hex_digits(), +//! ); //! -//! assert_eq!(usize::MIN.count_digits(), u8::MIN.count_digits()); -//! assert_eq!(usize::MAX.count_digits(), u8::MAX.count_digits()); -//! assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU8::MIN.count_digits()); -//! assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU8::MAX.count_digits()); +//! for radix in 2..=16 { +//! match radix { +//! 10 => assert_eq!( +//! 0xF00D_i32.count_digits_radix(radix), +//! 0xF00D_i32.wrapping_neg().count_digits_radix(radix), +//! ), +//! _ => assert_ne!( +//! 0xBAD_i32.count_digits_radix(radix), +//! 0xBAD_i32.wrapping_neg().count_digits_radix(radix), +//! ), +//! } //! } -//! ``` +//! ```` use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; -/// Count the decimal digits of an integer. +/// A [no_std](https://docs.rust-embedded.org/book/intro/no-std.html) trait to count +/// the digits of an integer in various number bases. pub trait CountDigits: Copy + Sized { /// The type of integer that should be passed in to the /// [count_digits_radix()](CountDigits::count_digits_radix) function. @@ -335,6 +302,11 @@ pub trait CountDigits: Copy + Sized { fn count_octal_digits(self) -> u32; /// Returns the count of decimal digits in an integer. + /// + /// ###### Note + /// + /// Counts digits only: the negative sign for negative numbers is not counted. + /// /// ### Examples /// ```rust /// use count_digits::CountDigits; From 734bc27f0dfa76f90fdcfd36776427f246c9f025 Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 10/12] Update README.md --- README.md | 164 ++++++++++++++++++++++-------------------------------- 1 file changed, 67 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 94c829c0d..30abee654 100644 --- a/README.md +++ b/README.md @@ -1,109 +1,79 @@ -# CountDigits -A Rust trait to count the decimal digits of integers +# count-digits ---- +## CountDigits +A [no_std](https://docs.rust-embedded.org/book/intro/no-std.html) trait to count +the digits of an integer in various number bases. + +Compatible with all primitive integer types and all non-zero integer types. + +##### Examples ```rust use count_digits::CountDigits; -use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; -use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; - -assert_eq!(03, i8::MIN.count_digits()); -assert_eq!(03, i8::MAX.count_digits()); -assert_eq!(03, NonZeroI8::MIN.count_digits()); -assert_eq!(03, NonZeroI8::MAX.count_digits()); - -assert_eq!(01, u8::MIN.count_digits()); -assert_eq!(03, u8::MAX.count_digits()); -assert_eq!(01, NonZeroU8::MIN.count_digits()); -assert_eq!(03, NonZeroU8::MAX.count_digits()); - -assert_eq!(05, i16::MIN.count_digits()); -assert_eq!(05, i16::MAX.count_digits()); -assert_eq!(05, NonZeroI16::MIN.count_digits()); -assert_eq!(05, NonZeroI16::MAX.count_digits()); - -assert_eq!(01, u16::MIN.count_digits()); -assert_eq!(05, u16::MAX.count_digits()); -assert_eq!(01, NonZeroU16::MIN.count_digits()); -assert_eq!(05, NonZeroU16::MAX.count_digits()); - -assert_eq!(10, i32::MIN.count_digits()); -assert_eq!(10, i32::MAX.count_digits()); -assert_eq!(10, NonZeroI32::MIN.count_digits()); -assert_eq!(10, NonZeroI32::MAX.count_digits()); - -assert_eq!(01, u32::MIN.count_digits()); -assert_eq!(10, u32::MAX.count_digits()); -assert_eq!(01, NonZeroU32::MIN.count_digits()); -assert_eq!(10, NonZeroU32::MAX.count_digits()); - -assert_eq!(19, i64::MIN.count_digits()); -assert_eq!(19, i64::MAX.count_digits()); -assert_eq!(19, NonZeroI64::MIN.count_digits()); -assert_eq!(19, NonZeroI64::MAX.count_digits()); - -assert_eq!(01, u64::MIN.count_digits()); -assert_eq!(20, u64::MAX.count_digits()); -assert_eq!(01, NonZeroU64::MIN.count_digits()); -assert_eq!(20, NonZeroU64::MAX.count_digits()); - -assert_eq!(39, i128::MIN.count_digits()); -assert_eq!(39, i128::MAX.count_digits()); -assert_eq!(39, NonZeroI128::MIN.count_digits()); -assert_eq!(39, NonZeroI128::MAX.count_digits()); - -assert_eq!(01, u128::MIN.count_digits()); -assert_eq!(39, u128::MAX.count_digits()); -assert_eq!(01, NonZeroU128::MIN.count_digits()); -assert_eq!(39, NonZeroU128::MAX.count_digits()); - -#[cfg(target_pointer_width = "64")] { - assert_eq!(isize::MIN.count_digits(), i64::MIN.count_digits()); - assert_eq!(isize::MAX.count_digits(), i64::MAX.count_digits()); - assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI64::MIN.count_digits()); - assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI64::MAX.count_digits()); - - assert_eq!(usize::MIN.count_digits(), u64::MIN.count_digits()); - assert_eq!(usize::MAX.count_digits(), u64::MAX.count_digits()); - assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU64::MIN.count_digits()); - assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU64::MAX.count_digits()); -} +use core::num::NonZeroIsize; -#[cfg(target_pointer_width = "32")] { - assert_eq!(isize::MIN.count_digits(), i32::MIN.count_digits()); - assert_eq!(isize::MAX.count_digits(), i32::MAX.count_digits()); - assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI32::MIN.count_digits()); - assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI32::MAX.count_digits()); +assert_eq!(16, 0b1111000000001101.count_bits()); +assert_eq!(16, 0b1111000000001101.count_digits_radix(2_u32)); - assert_eq!(usize::MIN.count_digits(), u32::MIN.count_digits()); - assert_eq!(usize::MAX.count_digits(), u32::MAX.count_digits()); - assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU32::MIN.count_digits()); - assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU32::MAX.count_digits()); -} +assert_eq!(06, 0o170015.count_octal_digits()); +assert_eq!(06, 0o170015.count_digits_radix(8_u32)); -#[cfg(target_pointer_width = "16")] { - assert_eq!(isize::MIN.count_digits(), i16::MIN.count_digits()); - assert_eq!(isize::MAX.count_digits(), i16::MAX.count_digits()); - assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI16::MIN.count_digits()); - assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI16::MAX.count_digits()); +assert_eq!(05, 61453.count_digits()); +assert_eq!(05, 61453.count_digits_radix(10_u32)); - assert_eq!(usize::MIN.count_digits(), u16::MIN.count_digits()); - assert_eq!(usize::MAX.count_digits(), u16::MAX.count_digits()); - assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU16::MIN.count_digits()); - assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU16::MAX.count_digits()); -} +assert_eq!(04, 0xF00D.count_hex_digits()); +assert_eq!(04, 0xF00D.count_digits_radix(16_u32)); + +assert_eq!( + 0xF00D_isize.count_digits(), + NonZeroIsize::new(0xF00D).unwrap().count_digits(), +); +``` -#[cfg(target_pointer_width = "8")] { - assert_eq!(isize::MIN.count_digits(), i8::MIN.count_digits()); - assert_eq!(isize::MAX.count_digits(), i8::MAX.count_digits()); - assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI8::MIN.count_digits()); - assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI8::MAX.count_digits()); +###### Note - assert_eq!(usize::MIN.count_digits(), u8::MIN.count_digits()); - assert_eq!(usize::MAX.count_digits(), u8::MAX.count_digits()); - assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU8::MIN.count_digits()); - assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU8::MAX.count_digits()); +Be mindful with negative signed integers in non-decimal number bases. + +Since negative decimal numbers are represented with a negative sign, +the decimal digit count of a negative number will be equal to its +positive counterpart. + +```rust +assert_eq!( + 0xF00D_i32.count_digits(), + 0xF00D_i32.wrapping_neg().count_digits(), +); +```` + +However, a negative number using a different radix will not have the +same count of digits as its positive counterpart. + +```rust +assert_ne!( + 0xBAD_i32.count_bits(), + 0xBAD_i32.wrapping_neg().count_bits(), +); +assert_ne!( + 0xBAD_i32.count_octal_digits(), + 0xBAD_i32.wrapping_neg().count_octal_digits(), +); +assert_ne!( + 0xBAD_i32.count_hex_digits(), + 0xBAD_i32.wrapping_neg().count_hex_digits(), +); + +for radix in 2..=16 { + match radix { + 10 => assert_eq!( + 0xF00D_i32.count_digits_radix(radix), + 0xF00D_i32.wrapping_neg().count_digits_radix(radix), + ), + _ => assert_ne!( + 0xBAD_i32.count_digits_radix(radix), + 0xBAD_i32.wrapping_neg().count_digits_radix(radix), + ), + } } -``` +```` +License: MIT From 1190b93860cf4f22f4ee3322503daf2768f07518 Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 22:39:11 -0600 Subject: [PATCH 11/12] Bump minimum supported Rust version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 21caf17b6..809de9046 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ keywords = ["decimal", "digit", "count", "integer", "trait"] categories = [ "algorithms", "mathematics", "no-std" ] license = "MIT" edition = "2021" -rust-version = "1.67.1" +rust-version = "1.71.1" [dev-dependencies] paste = "1.0.14" From 2d14b1bfd8ca5287633f002c50997e5d9feb1a82 Mon Sep 17 00:00:00 2001 From: Erik Nordin Date: Tue, 23 Jan 2024 23:19:28 -0600 Subject: [PATCH 12/12] v0.2.0 Release