#![cfg_attr(not(test), no_std)]
#![allow(clippy::zero_prefixed_literal)]
use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
pub trait CountDigits: Copy + Sized {
type Radix;
fn count_bits(self) -> u32;
fn count_octal_digits(self) -> u32;
fn count_hex_digits(self) -> u32;
fn count_digits(self) -> usize;
fn count_digits_radix(self, radix: Self::Radix) -> usize;
fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize>;
}
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)]
fn count_bits(self) -> u32 {
if self.is_negative() {
$min_value_bits
} else {
1 + self.checked_ilog2().unwrap_or_default()
}
}
#[inline(always)]
fn count_octal_digits(self) -> u32 {
if self.is_negative() {
$min_value_octal_digits
} else {
1 + self.checked_ilog2().unwrap_or_default() / 3
}
}
#[inline(always)]
fn count_hex_digits(self) -> u32 {
if self.is_negative() {
$min_value_hex_digits
} else {
1 + self.checked_ilog2().unwrap_or_default() / 4
}
}
#[inline(always)]
fn count_digits(self) -> usize {
1 + self.abs_diff(0).checked_ilog10().unwrap_or_default() as usize
}
#[inline(always)]
fn count_digits_radix(self, radix: Self::Radix) -> usize {
match radix {
0 | 1 => panic!("base of integer logarithm must be at least 2"),
02 => self.count_bits() as usize,
08 => self.count_octal_digits() as usize,
10 => self.count_digits(),
16 => self.count_hex_digits() as usize,
__ => {
if self.is_negative() {
1 + <$primitive_type>::MIN.abs_diff(0).ilog(radix) as usize
} else {
1 + self.abs_diff(0).checked_ilog(radix).unwrap_or_default() as usize
}
}
}
}
#[inline(always)]
fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
match radix {
0 | 1 => None,
radix => Some(self.count_digits_radix(radix)),
}
}
}
impl CountDigits for $non_zero_type {
type Radix = $radix_type;
#[inline(always)]
fn count_bits(self) -> u32 {
if self.is_negative() {
$min_value_bits
} else {
1 + self.get().ilog2()
}
}
#[inline(always)]
fn count_octal_digits(self) -> u32 {
if self.is_negative() {
$min_value_octal_digits
} else {
1 + self.get().ilog2() / 3
}
}
#[inline(always)]
fn count_hex_digits(self) -> u32 {
if self.is_negative() {
$min_value_hex_digits
} else {
1 + self.get().ilog2() / 4
}
}
#[inline(always)]
fn count_digits(self) -> usize {
1 + self.get().abs_diff(0).ilog10() as usize
}
#[inline(always)]
fn count_digits_radix(self, radix: Self::Radix) -> usize {
match radix {
0 | 1 => panic!("base of integer logarithm must be at least 2"),
02 => self.count_bits() as usize,
08 => self.count_octal_digits() as usize,
10 => self.count_digits(),
16 => self.count_hex_digits() as usize,
__ => {
if self.is_negative() {
1 + <$primitive_type>::MIN.abs_diff(0).ilog(radix) as usize
} else {
1 + self.get().abs_diff(0).ilog(radix) as usize
}
}
}
}
#[inline(always)]
fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
match radix {
0 | 1 => None,
radix => Some(self.count_digits_radix(radix)),
}
}
}
};
(
primitive_type = $primitive_type:ty,
non_zero_type = $non_zero_type:ty,
) => {
impl CountDigits for $primitive_type {
type Radix = $primitive_type;
#[inline(always)]
fn count_bits(self) -> u32 {
1 + self.checked_ilog2().unwrap_or_default()
}
#[inline(always)]
fn count_octal_digits(self) -> u32 {
1 + self.checked_ilog2().unwrap_or_default() / 3
}
#[inline(always)]
fn count_hex_digits(self) -> u32 {
1 + self.checked_ilog2().unwrap_or_default() / 4
}
#[inline(always)]
fn count_digits(self) -> usize {
1 + self.checked_ilog10().unwrap_or_default() as usize
}
#[inline(always)]
fn count_digits_radix(self, radix: Self::Radix) -> usize {
match radix {
0 | 1 => panic!("base of integer logarithm must be at least 2"),
02 => self.count_bits() as usize,
08 => self.count_octal_digits() as usize,
10 => self.count_digits(),
16 => self.count_hex_digits() as usize,
__ => 1 + self.checked_ilog(radix).unwrap_or_default() as usize,
}
}
#[inline(always)]
fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
match radix {
0 | 1 => None,
radix => Some(self.count_digits_radix(radix)),
}
}
}
impl CountDigits for $non_zero_type {
type Radix = $primitive_type;
#[inline(always)]
fn count_bits(self) -> u32 {
1 + self.ilog2()
}
#[inline(always)]
fn count_octal_digits(self) -> u32 {
1 + self.get().ilog2() / 3
}
#[inline(always)]
fn count_hex_digits(self) -> u32 {
1 + self.get().ilog2() / 4
}
#[inline(always)]
fn count_digits(self) -> usize {
1 + self.ilog10() as usize
}
#[inline(always)]
fn count_digits_radix(self, radix: Self::Radix) -> usize {
match radix {
0 | 1 => panic!("base of integer logarithm must be at least 2"),
02 => self.count_bits() as usize,
08 => self.count_octal_digits() as usize,
10 => self.count_digits(),
16 => self.count_hex_digits() as usize,
_ => 1 + self.get().ilog(radix) as usize,
}
}
#[inline(always)]
fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
match radix {
0 | 1 => None,
radix => Some(self.count_digits_radix(radix)),
}
}
}
};
}
impl<T: CountDigits> CountDigits for &T {
type Radix = <T as CountDigits>::Radix;
#[inline(always)]
fn count_bits(self) -> u32 {
(*self).count_bits()
}
#[inline(always)]
fn count_octal_digits(self) -> u32 {
(*self).count_octal_digits()
}
#[inline(always)]
fn count_digits(self) -> usize {
(*self).count_digits()
}
#[inline(always)]
fn count_hex_digits(self) -> u32 {
(*self).count_hex_digits()
}
#[inline(always)]
fn count_digits_radix(self, radix: Self::Radix) -> usize {
(*self).count_digits_radix(radix)
}
#[inline(always)]
fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
(*self).checked_count_digits_radix(radix)
}
}
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,
}
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,
}
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,
}
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,
}
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,
}
#[cfg(target_pointer_width = "64")]
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,
}
#[cfg(target_pointer_width = "32")]
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,
}
#[cfg(target_pointer_width = "16")]
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,
}
#[cfg(target_pointer_width = "8")]
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,
}
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 {
use super::*;
use paste::paste;
macro_rules! binary_string_count {
($n:expr) => {
format!("{:b}", $n).len() as u32
};
}
macro_rules! octal_string_count {
($n:expr) => {
format!("{:o}", $n).len() as u32
};
}
macro_rules! decimal_string_count {
($n:expr) => {{
let string = format!("{}", $n);
string.strip_prefix('-').unwrap_or(&string).len()
}};
}
macro_rules! hex_string_count {
($n:expr) => {
format!("{:x}", $n).len() as u32
};
}
macro_rules! assert_min {
($type:ty, count_bits) => {
assert_eq!(
<$type>::MIN.count_bits(),
binary_string_count!(<$type>::MIN)
);
assert_eq!(
<$type>::MIN.count_digits_radix(2),
binary_string_count!(<$type>::MIN) as usize,
);
};
($type:ty, count_octal_digits) => {
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) as usize,
);
};
($type:ty, count_digits) => {
assert_eq!(
<$type>::MIN.count_digits(),
decimal_string_count!(<$type>::MIN)
);
assert_eq!(
<$type>::MIN.count_digits_radix(10),
decimal_string_count!(<$type>::MIN),
);
};
($type:ty, count_hex_digits) => {
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) as usize,
);
};
}
macro_rules! assert_max {
($type:ty, count_bits) => {
assert_eq!(
<$type>::MAX.count_bits(),
binary_string_count!(<$type>::MAX)
);
assert_eq!(
<$type>::MAX.count_digits_radix(2),
binary_string_count!(<$type>::MAX) as usize,
);
};
($type:ty, count_octal_digits) => {
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) as usize,
);
};
($type:ty, count_digits) => {
assert_eq!(
<$type>::MAX.count_digits(),
decimal_string_count!(<$type>::MAX)
);
assert_eq!(
<$type>::MAX.count_digits_radix(10),
decimal_string_count!(<$type>::MAX),
);
};
($type:ty, count_hex_digits) => {
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) as usize,
);
};
}
macro_rules! assert_representations {
($n:expr, count_bits) => {
assert_eq!($n.count_bits(), binary_string_count!($n));
assert_eq!($n.count_digits_radix(2), binary_string_count!($n) as usize);
};
($n:expr, count_octal_digits) => {
assert_eq!($n.count_octal_digits(), octal_string_count!($n));
assert_eq!($n.count_digits_radix(8), octal_string_count!($n) as usize);
};
($n:expr, count_digits) => {
assert_eq!($n.count_digits(), decimal_string_count!($n));
assert_eq!($n.count_digits_radix(10), decimal_string_count!($n));
};
($n:expr, count_hex_digits) => {
assert_eq!($n.count_hex_digits(), hex_string_count!($n));
assert_eq!($n.count_digits_radix(16), hex_string_count!($n) as usize);
};
($n:expr, count_digits_radix_ordering) => {
assert!([
$n.count_digits_radix(02),
$n.count_digits_radix(03),
$n.count_digits_radix(04),
$n.count_digits_radix(05),
$n.count_digits_radix(06),
$n.count_digits_radix(07),
$n.count_digits_radix(08),
$n.count_digits_radix(09),
$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]));
};
($n:expr, checked_count_digits_radix_ordering) => {
assert!([
$n.checked_count_digits_radix(02).unwrap(),
$n.checked_count_digits_radix(03).unwrap(),
$n.checked_count_digits_radix(04).unwrap(),
$n.checked_count_digits_radix(05).unwrap(),
$n.checked_count_digits_radix(06).unwrap(),
$n.checked_count_digits_radix(07).unwrap(),
$n.checked_count_digits_radix(08).unwrap(),
$n.checked_count_digits_radix(09).unwrap(),
$n.checked_count_digits_radix(11).unwrap(),
$n.checked_count_digits_radix(12).unwrap(),
$n.checked_count_digits_radix(13).unwrap(),
$n.checked_count_digits_radix(14).unwrap(),
$n.checked_count_digits_radix(15).unwrap(),
$n.checked_count_digits_radix(16).unwrap(),
]
.windows(2)
.all(|window| window[0] >= window[1]));
};
}
macro_rules! lower_bound {
($type:ty) => {
-100_000 as $type
};
}
macro_rules! upper_bound {
($type:ty) => {
100_000 as $type
};
}
macro_rules! min_or_lower_bound {
(i8) => {
i8::MIN
};
(i16) => {
i16::MIN
};
(isize) => {{
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
const fn min_or_lower_bound() -> isize {
lower_bound!(isize)
}
#[cfg(any(target_pointer_width = "16", target_pointer_width = "8"))]
const fn min_or_lower_bound() -> isize {
isize::MIN
}
min_or_lower_bound()
}};
($type:ty) => {
lower_bound!($type)
};
}
macro_rules! max_or_upper_bound {
(i8) => {
i8::MAX
};
(i16) => {
i16::MAX
};
(u8) => {
u8::MAX
};
(u16) => {
u16::MAX
};
(isize) => {{
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
const fn max_or_upper_bound() -> isize {
upper_bound!(isize)
}
#[cfg(any(target_pointer_width = "16", target_pointer_width = "8"))]
const fn max_or_upper_bound() -> isize {
isize::MAX
}
max_or_upper_bound()
}};
(usize) => {{
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
const fn max_or_upper_bound() -> usize {
upper_bound!(usize)
}
#[cfg(any(target_pointer_width = "16", target_pointer_width = "8"))]
const fn max_or_upper_bound() -> usize {
isize::MAX
}
max_or_upper_bound()
}};
($type:ty) => {
upper_bound!($type)
};
}
macro_rules! radix_boundaries {
($type:ty, $radix:expr) => {
std::iter::successors(Some($radix as $type), move |n| {
n.checked_mul($radix as $type)
})
.map(|n| [n - 1, n])
};
}
#[test]
fn helper_radix_boundaries() {
assert_eq!(
radix_boundaries!(i8, 2).collect::<Vec<_>>(),
[[1, 2], [3, 4], [7, 8], [15, 16], [31, 32], [63, 64]],
);
assert_eq!(
radix_boundaries!(i16, 10).collect::<Vec<_>>(),
[[9, 10], [99, 100], [999, 1000], [9999, 10000]],
);
assert_eq!(
radix_boundaries!(i16, 16).collect::<Vec<_>>(),
[[0xF, 0x10], [0xFF, 0x100], [0xFFF, 0x1000]],
);
}
fn increasing_pairs() -> impl Iterator<Item = (usize, usize)> {
std::iter::successors(Some(1usize), move |n| n.checked_add(1))
.zip(std::iter::successors(Some(2usize), move |n| {
n.checked_add(1)
}))
}
#[test]
fn helper_increasing_pairs() {
assert_eq!(
increasing_pairs().take(5).collect::<Vec<_>>(),
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)],
);
}
macro_rules! min_and_max {
($type:ty, $non_zero_type:ty) => {
min_and_max!($type, $non_zero_type, count_bits);
min_and_max!($type, $non_zero_type, count_octal_digits);
min_and_max!($type, $non_zero_type, count_digits);
min_and_max!($type, $non_zero_type, count_hex_digits);
};
($type:ty, $non_zero_type:ty, $function:ident) => {
paste! {
#[test]
fn [<$type _min_ $function>]() {
assert_min!($type, $function);
}
#[test]
fn [<$type _max_ $function>]() {
assert_max!($type, $function);
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _min_ $function>]() {
assert_min!($non_zero_type, $function);
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _max_ $function>]() {
assert_max!($non_zero_type, $function);
}
}
};
}
macro_rules! iteration {
($signage:ident, $type:ty, $non_zero_type:ty) => {
iteration!($signage, $type, $non_zero_type, count_bits);
iteration!($signage, $type, $non_zero_type, count_octal_digits);
iteration!($signage, $type, $non_zero_type, count_digits);
iteration!($signage, $type, $non_zero_type, count_hex_digits);
iteration!($signage, $type, $non_zero_type, count_digits_radix_ordering);
iteration!(
$signage,
$type,
$non_zero_type,
checked_count_digits_radix_ordering
);
};
(signed, $type:ty, $non_zero_type:ty, $function:ident) => {
paste! {
#[test]
fn [<$type _iteration_ $function>]() {
let max = max_or_upper_bound!($type);
let min = min_or_lower_bound!($type);
for n in min..=max {
assert_representations!(n, $function);
}
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _iteration_ $function>]() {
let max = max_or_upper_bound!($type);
let min = min_or_lower_bound!($type);
for n in min..=max {
if n == 0 { continue; }
let n = $non_zero_type::new(n).unwrap();
assert_representations!(n, $function);
}
}
}
};
(unsigned, $type:ty, $non_zero_type:ty, $function:ident) => {
paste! {
#[test]
fn [<$type _iteration_ $function>]() {
let max = max_or_upper_bound!($type);
for n in $type::MIN..=max {
assert_representations!(n, $function);
}
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _iteration_ $function>]() {
let max = max_or_upper_bound!($type);
for n in $non_zero_type::MIN.get()..=max {
let n = $non_zero_type::new(n).unwrap();
assert_representations!(n, $function);
}
}
}
};
}
macro_rules! pass_by_reference {
($type:ty, $non_zero_type:ty) => {
pass_by_reference!($type, $non_zero_type, count_bits);
pass_by_reference!($type, $non_zero_type, count_octal_digits);
pass_by_reference!($type, $non_zero_type, count_hex_digits);
pass_by_reference!($type, $non_zero_type, count_digits);
pass_by_reference!($type, $non_zero_type, count_digits_radix);
pass_by_reference!($type, $non_zero_type, checked_count_digits_radix);
};
($type:ty, $non_zero_type:ty, count_digits_radix) => {
paste! {
#[test]
fn [<$type _pass_by_reference_count_digits_radix>]() {
for radix in 2..20 {
for n in radix_boundaries!($type, radix).flatten() {
assert_eq!(CountDigits::count_digits_radix(n, radix), CountDigits::count_digits_radix(&n, radix));
}
}
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _pass_by_reference_count_digits_radix>]() {
for radix in 2..20 {
for n in radix_boundaries!($type, radix).flatten() {
let n = $non_zero_type::new(n).unwrap();
assert_eq!(CountDigits::count_digits_radix(n, radix), CountDigits::count_digits_radix(&n, radix));
}
}
}
}
};
($type:ty, $non_zero_type:ty, checked_count_digits_radix) => {
paste! {
#[test]
fn [<$type _pass_by_reference_checked_count_digits_radix>]() {
for radix in 2..20 {
for n in radix_boundaries!($type, radix).flatten() {
assert_eq!(CountDigits::checked_count_digits_radix(n, radix), CountDigits::checked_count_digits_radix(&n, radix));
}
}
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _pass_by_reference_checked_count_digits_radix>]() {
for radix in 2..20 {
for n in radix_boundaries!($type, radix).flatten() {
let n = $non_zero_type::new(n).unwrap();
assert_eq!(CountDigits::checked_count_digits_radix(n, radix), CountDigits::checked_count_digits_radix(&n, radix));
}
}
}
}
};
($type:ty, $non_zero_type:ty, $function:ident) => {
paste! {
#[test]
fn [<$type _pass_by_reference_ $function>]() {
for radix in 2..20 {
for n in radix_boundaries!($type, radix).flatten() {
assert_eq!(CountDigits::$function(n), CountDigits::$function(&n));
}
}
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _pass_by_reference_ $function>]() {
for radix in 2..20 {
for n in radix_boundaries!($type, radix).flatten() {
let n = $non_zero_type::new(n).unwrap();
assert_eq!(CountDigits::$function(n), CountDigits::$function(&n));
}
}
}
}
};
}
macro_rules! invalid_radix {
($type:ty, $non_zero_type:ty) => {
invalid_radix!(0, $type, $non_zero_type);
invalid_radix!(1, $type, $non_zero_type);
};
($radix:expr, $type:ty, $non_zero_type:ty) => {
paste! {
#[test]
#[should_panic(expected = "base of integer logarithm must be at least 2")]
fn [<$type _invalid_radix_ $radix>]() {
(1 as $type).count_digits_radix($radix);
}
#[test]
fn [<$type _invalid_radix_ $radix _checked>]() {
assert!((1 as $type).checked_count_digits_radix($radix).is_none());
}
#[test]
#[allow(non_snake_case)]
#[should_panic(expected = "base of integer logarithm must be at least 2")]
fn [<$non_zero_type _invalid_radix_ $radix>]() {
$non_zero_type::new(1).unwrap().count_digits_radix($radix);
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _invalid_radix_ $radix _checked>]() {
assert!($non_zero_type::new(1).unwrap().checked_count_digits_radix($radix).is_none());
}
}
};
}
macro_rules! boundaries_for_radix {
($type:ty, $non_zero_type:ty) => {
boundaries_for_radix!(02, $type, $non_zero_type);
boundaries_for_radix!(03, $type, $non_zero_type);
boundaries_for_radix!(04, $type, $non_zero_type);
boundaries_for_radix!(05, $type, $non_zero_type);
boundaries_for_radix!(06, $type, $non_zero_type);
boundaries_for_radix!(07, $type, $non_zero_type);
boundaries_for_radix!(08, $type, $non_zero_type);
boundaries_for_radix!(09, $type, $non_zero_type);
boundaries_for_radix!(10, $type, $non_zero_type);
boundaries_for_radix!(11, $type, $non_zero_type);
boundaries_for_radix!(12, $type, $non_zero_type);
boundaries_for_radix!(13, $type, $non_zero_type);
boundaries_for_radix!(14, $type, $non_zero_type);
boundaries_for_radix!(15, $type, $non_zero_type);
boundaries_for_radix!(16, $type, $non_zero_type);
boundaries_for_radix!(17, $type, $non_zero_type);
boundaries_for_radix!(18, $type, $non_zero_type);
boundaries_for_radix!(19, $type, $non_zero_type);
};
($radix:expr, $type:ty, $non_zero_type:ty) => {
paste! {
#[test]
fn [<$type _boundaries_for_radix_ $radix>]() {
assert!(
radix_boundaries!($type, $radix)
.map(|[n, m]| (n.count_digits_radix($radix), m.count_digits_radix($radix)))
.zip(increasing_pairs())
.all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
lhs_expected == lhs_actual && rhs_expected == rhs_actual
})
)
}
#[test]
fn [<$type _boundaries_for_radix_ $radix _checked>]() {
assert!(
radix_boundaries!($type, $radix)
.map(|[n, m]| (n.checked_count_digits_radix($radix), m.checked_count_digits_radix($radix)))
.zip(increasing_pairs())
.all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
lhs_expected == lhs_actual.unwrap() && rhs_expected == rhs_actual.unwrap()
})
)
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _boundaries_for_radix_ $radix>]() {
assert!(
radix_boundaries!($type, $radix)
.map(|[n, m]| (<$non_zero_type>::new(n).unwrap(), <$non_zero_type>::new(m).unwrap()))
.map(|(n, m)| (n.count_digits_radix($radix), m.count_digits_radix($radix)))
.zip(increasing_pairs())
.all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
lhs_expected == lhs_actual && rhs_expected == rhs_actual
})
)
}
#[test]
#[allow(non_snake_case)]
fn [<$non_zero_type _boundaries_for_radix_ $radix _checked>]() {
assert!(
radix_boundaries!($type, $radix)
.map(|[n, m]| (<$non_zero_type>::new(n).unwrap(), <$non_zero_type>::new(m).unwrap()))
.map(|(n, m)| (n.checked_count_digits_radix($radix), m.checked_count_digits_radix($radix)))
.zip(increasing_pairs())
.all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
lhs_expected == lhs_actual.unwrap() && rhs_expected == rhs_actual.unwrap()
})
)
}
}
};
}
macro_rules! add_test {
($name:ident, $($args:tt)+) => {
$name!($($args)*);
};
}
add_test!(boundaries_for_radix, i8, NonZeroI8);
add_test!(boundaries_for_radix, i16, NonZeroI16);
add_test!(boundaries_for_radix, i32, NonZeroI32);
add_test!(boundaries_for_radix, i64, NonZeroI64);
add_test!(boundaries_for_radix, i128, NonZeroI128);
add_test!(boundaries_for_radix, isize, NonZeroIsize);
add_test!(boundaries_for_radix, u8, NonZeroU8);
add_test!(boundaries_for_radix, u16, NonZeroU16);
add_test!(boundaries_for_radix, u32, NonZeroU32);
add_test!(boundaries_for_radix, u64, NonZeroU64);
add_test!(boundaries_for_radix, u128, NonZeroU128);
add_test!(boundaries_for_radix, usize, NonZeroUsize);
add_test!(invalid_radix, i8, NonZeroI8);
add_test!(invalid_radix, i16, NonZeroI16);
add_test!(invalid_radix, i32, NonZeroI32);
add_test!(invalid_radix, i64, NonZeroI64);
add_test!(invalid_radix, isize, NonZeroIsize);
add_test!(invalid_radix, u8, NonZeroU8);
add_test!(invalid_radix, u16, NonZeroU16);
add_test!(invalid_radix, u32, NonZeroU32);
add_test!(invalid_radix, u64, NonZeroU64);
add_test!(invalid_radix, usize, NonZeroUsize);
add_test!(iteration, signed, i8, NonZeroI8);
add_test!(iteration, signed, i16, NonZeroI16);
add_test!(iteration, signed, i32, NonZeroI32);
add_test!(iteration, signed, i64, NonZeroI64);
add_test!(iteration, signed, i128, NonZeroI128);
add_test!(iteration, signed, isize, NonZeroIsize);
add_test!(iteration, unsigned, u8, NonZeroU8);
add_test!(iteration, unsigned, u16, NonZeroU16);
add_test!(iteration, unsigned, u32, NonZeroU32);
add_test!(iteration, unsigned, u64, NonZeroU64);
add_test!(iteration, unsigned, u128, NonZeroU128);
add_test!(iteration, unsigned, usize, NonZeroUsize);
add_test!(min_and_max, i8, NonZeroI8);
add_test!(min_and_max, i16, NonZeroI16);
add_test!(min_and_max, i32, NonZeroI32);
add_test!(min_and_max, i64, NonZeroI64);
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!(pass_by_reference, i8, NonZeroI8);
add_test!(pass_by_reference, i16, NonZeroI16);
add_test!(pass_by_reference, i32, NonZeroI32);
add_test!(pass_by_reference, i64, NonZeroI64);
add_test!(pass_by_reference, i128, NonZeroI128);
add_test!(pass_by_reference, isize, NonZeroIsize);
add_test!(pass_by_reference, u8, NonZeroU8);
add_test!(pass_by_reference, u16, NonZeroU16);
add_test!(pass_by_reference, u32, NonZeroU32);
add_test!(pass_by_reference, u64, NonZeroU64);
add_test!(pass_by_reference, u128, NonZeroU128);
add_test!(pass_by_reference, usize, NonZeroUsize);
}