count_digits/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![allow(clippy::zero_prefixed_literal)]
3//! [![github]](https://github.com/nordzilla/count-digits)
4//! [![crates-io]](https://crates.io/crates/count-digits)
5//! [![docs-rs]](https://docs.rs/count-digits)
6//!
7//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
8//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
9//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
10//!
11//! [![license]](https://github.com/nordzilla/count-digits/blob/main/LICENSE)
12//! [![build]](https://github.com/nordzilla/count-digits/commits/main/)
13//! [![codecov]](https://app.codecov.io/gh/nordzilla/count-digits)
14//!
15//! [license]: https://img.shields.io/github/license/nordzilla/count-digits?style=flat-square&color=009050&label=License
16//! [build]: https://img.shields.io/github/actions/workflow/status/nordzilla/count-digits/rust.yml?style=flat-square&logo=github&color=009050&label=Build
17//! [codecov]: https://img.shields.io/codecov/c/github/nordzilla/count-digits?style=flat-square&logo=codecov&color=009050&label=Test+Coverage
18//!
19//! <br>
20//!
21//! [CountDigits](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html)
22//! is a [no-std](https://docs.rust-embedded.org/book/intro/no-std.html) trait with functions
23//! to determine the lengths of integers in various number bases.
24//!
25//! It is [implemented](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#foreign-impls)
26//! for all primitive integer types and all non-zero integer types.
27//!
28//! ```rust
29//! pub trait CountDigits: Copy + Sized {
30//!     /// The type of integer that should be used for radix arguments.
31//!     type Radix;
32//!
33//!     /// Returns the count of bits in an integer.
34//!     fn count_bits(self) -> u32;
35//!
36//!     /// Returns the count of octal digits in an integer.
37//!     fn count_octal_digits(self) -> u32;
38//!
39//!     /// Returns the count of hexadecimal digits in an integer.
40//!     fn count_hex_digits(self) -> u32;
41//!
42//!     /// Returns the count of decimal digits in an integer.
43//!     fn count_digits(self) -> usize;
44//!
45//!     /// Returns the count of digits in an integer for a given radix.
46//!     /// Panics if the provided radix is invalid.
47//!     fn count_digits_radix(self, radix: Self::Radix) -> usize;
48//!
49//!     /// Returns the count of digits in an integer for a given radix.
50//!     /// Returns None if the given radix is invalid.
51//!     fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize>;
52//! }
53//! ```
54//!
55//! ## Examples
56//!
57//! ```rust
58//! use count_digits::CountDigits;
59//!
60//! // Base 2
61//! assert_eq!(16, 0b1111000000001101.count_bits());
62//! assert_eq!(16, 0b1111000000001101.count_digits_radix(2_u32));
63//!
64//! // Base 8
65//! assert_eq!(06, 0o170015.count_octal_digits());
66//! assert_eq!(06, 0o170015.count_digits_radix(8_u32));
67//!
68//! // Base 10
69//! assert_eq!(05, 61453.count_digits());
70//! assert_eq!(05, 61453.count_digits_radix(10_u32));
71//!
72//! // Base 16
73//! assert_eq!(04, 0xF00D.count_hex_digits());
74//! assert_eq!(04, 0xF00D.count_digits_radix(16_u32));
75//! ```
76//!
77//! #### Functions That Return u32
78//!
79//! Named functions for which the radix is a power of two return
80//! [u32](https://doc.rust-lang.org/core/primitive.u32.html) for
81//! compatibility with Rust's bitwise functions and constants.
82//!
83//! * [count_bits()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_bits)
84//! * [count_octal_digits()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_octal_digits)
85//! * [count_hex_digits()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_hex_digits)
86//!
87//! ```rust
88//! # use count_digits::CountDigits;
89//! assert_eq!(0b1011___u8.count_bits(),   u8::BITS - 0b1011___u8.leading_zeros());
90//! assert_eq!(0b1011__i32.count_bits(),  i32::BITS - 0b1011__i32.leading_zeros());
91//! assert_eq!(0b1011_u128.count_bits(), u128::BITS - 0b1011_u128.leading_zeros());
92//! ```
93//!
94//! #### Functions That Return usize
95//!
96//! Functions that are not inherently meaningful in a bitwise context return [usize](https://doc.rust-lang.org/core/primitive.usize.html)
97//! for compatibility with Rust's formatting functions and macros.
98//!
99//! * [count_digits()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_digits)
100//! * [count_digits_radix()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_digits_radix)
101//! * [checked_count_digits_radix()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.checked_count_digits_radix)
102//!
103//! ```rust
104//! # use count_digits::CountDigits;
105//! let numbers = [2, 3, 13, 103, 1337];
106//! let max_digits = numbers
107//!     .iter()
108//!     .map(CountDigits::count_digits)
109//!     .max()
110//!     .unwrap();
111//!
112//! for n in numbers {
113//!     assert_eq!(4, format!("{n:>max_digits$}").chars().count());
114//! }
115//! ```
116//!
117//! When formatting binary, octal, or hexadecimal numbers, the
118//! [count_digits_radix(2 | 8 | 16)](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_digits_radix)
119//! and [checked_count_digits_radix(2 | 8 | 16)](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.checked_count_digits_radix)
120//! functions can be used in place of [count_bits()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_bits),
121//! [count_octal_digits()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_octal_digits), and
122//! [count_hex_digits()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_hex_digits)
123//! to retrieve the desired count directly as a [usize](https://doc.rust-lang.org/core/primitive.usize.html).
124//!
125//! ```rust
126//! # use count_digits::CountDigits;
127//! let numbers = [0b1, 0b10, 0b101, 0b1011];
128//! let max_bits = numbers
129//!     .iter()
130//!     .map(|n| n.count_digits_radix(2u32))
131//!     .max()
132//!     .unwrap();
133//!
134//! for n in numbers {
135//!     assert_eq!(4, format!("{n:>max_bits$}").chars().count());
136//! }
137//! ```
138//!
139//! #### Invalid Radix Values
140//!
141//! Values passed to [count_digits_radix()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_digits_radix)
142//! and [checked_count_digits_radix()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.checked_count_digits_radix)
143//! must be greater than or equal to 2.
144//!
145//! * [count_digits_radix()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.count_digits_radix)
146//! will [panic](https://doc.rust-lang.org/stable/core/macro.panic.html) if given an invalid radix.
147//!
148//! ```rust
149//! # use count_digits::CountDigits;
150//! for n in 0..100 {
151//!     assert!(std::panic::catch_unwind(|| n.count_digits_radix(0_u32)).is_err());
152//!     assert!(std::panic::catch_unwind(|| n.count_digits_radix(1_u32)).is_err());
153//! }
154//! ```
155//!
156//! * [checked_count_digits_radix()](https://docs.rs/count-digits/latest/count_digits/trait.CountDigits.html#tymethod.checked_count_digits_radix)
157//! will return [None](https://doc.rust-lang.org/stable/core/option/enum.Option.html#variant.None) if given an invalid radix.
158//!
159//! ```rust
160//! # use count_digits::CountDigits;
161//! for n in 0..100 {
162//!     assert!(n.checked_count_digits_radix(0_u32).is_none());
163//!     assert!(n.checked_count_digits_radix(1_u32).is_none());
164//! }
165//! ```
166//!
167//! #### Negative Numbers
168//!
169//! Since negative numbers represented in base 10 are displayed with a negative sign,
170//! the base-10 digit count of a positive number will be equal to the base-10 digit count
171//! of the number's negated value, assuming no wrapping occurs.
172//!
173//! ```rust
174//! # use count_digits::CountDigits;
175//! assert_eq!(
176//!     867_5309_i32.count_digits(),
177//!     867_5309_i32.wrapping_neg().count_digits(),
178//! );
179//! ```
180//!
181//! <div class="warning" style="text-align: left;">
182//!     The negative sign itself is not included in the count because
183//!     the negative sign is not a digit.
184//! </div>
185//!
186//! The digit counts of negative numbers represented in other bases reflect the
187//! [twos-complement](https://en.wikipedia.org/wiki/Two%27s_complement) representation,
188//! and the digit count of a positive number will _not_ be the same as the count
189//! of its negated value.
190//!
191//! ```rust
192//! # use count_digits::CountDigits;
193//! for radix in 2..=16 {
194//!     match radix {
195//!         10 => assert_eq!(
196//!             0xF00D_i32.count_digits_radix(radix),
197//!             0xF00D_i32.wrapping_neg().count_digits_radix(radix),
198//!         ),
199//!         _ => assert_ne!(
200//!             0xBAD_i32.count_digits_radix(radix),
201//!             0xBAD_i32.wrapping_neg().count_digits_radix(radix),
202//!         ),
203//!     }
204//! }
205//! ```
206//!
207//! This is consistent with Rust's display format.
208//! ```rust
209//! # use count_digits::CountDigits;
210//! // Base 2
211//! assert_eq!(01, format!("{:b}",  1_i32).chars().count());
212//! assert_eq!(32, format!("{:b}", -1_i32).chars().count());
213//!
214//! // Base 8
215//! assert_eq!(01, format!("{:o}",  1_i32).chars().count());
216//! assert_eq!(11, format!("{:o}", -1_i32).chars().count());
217//!
218//! // Base 10
219//! assert_eq!(01, format!("{  }",  1_i32).chars().count());
220//! assert_eq!(01, format!("{  }", -1_i32).strip_prefix('-').unwrap().chars().count());
221//!
222//! // Base 16
223//! assert_eq!(01, format!("{:x}",  1_i32).chars().count());
224//! assert_eq!(08, format!("{:x}", -1_i32).chars().count());
225//! ```
226//!
227//! ## Benchmarks
228//!
229//! * [table](https://nordzilla.github.io/count-digits)
230//! * [count_bits()](https://nordzilla.github.io/count-digits/count_bits/report/index.html)
231//! * [count_octal_digits()](https://nordzilla.github.io/count-digits/count_octal_digits/report/index.html)
232//! * [count_digits()](https://nordzilla.github.io/count-digits/count_digits/report/index.html)
233//! * [count_hex_digits()](https://nordzilla.github.io/count-digits/count_hex_digits/report/index.html)
234
235use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
236use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
237
238/// A [no-std](https://docs.rust-embedded.org/book/intro/no-std.html) trait to determine
239/// lengths of integers in various number bases.
240pub trait CountDigits: Copy + Sized {
241    /// The type of integer that should be passed to the
242    /// [count_digits_radix()](CountDigits::count_digits_radix) and
243    /// [checked_count_digits_radix()](CountDigits::checked_count_digits_radix) functions.
244    ///
245    /// This is always the corresponding unsigned primitive type for an integer of a given size.
246    ///
247    /// For example, [u8] is the [Radix](CountDigits::Radix) type for [i8], [u8], [NonZeroI8], and [NonZeroU8].
248    type Radix;
249
250    /// Returns the count of bits in an integer.
251    ///
252    /// # Examples
253    ///
254    /// ```rust
255    /// use count_digits::CountDigits;
256    /// # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
257    /// # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
258    ///
259    /// assert_eq!(008, i8::MIN.count_bits());
260    /// assert_eq!(007, i8::MAX.count_bits());
261    /// assert_eq!(008, NonZeroI8::MIN.count_bits());
262    /// assert_eq!(007, NonZeroI8::MAX.count_bits());
263    ///
264    /// assert_eq!(001, u8::MIN.count_bits());
265    /// assert_eq!(008, u8::MAX.count_bits());
266    /// assert_eq!(001, NonZeroU8::MIN.count_bits());
267    /// assert_eq!(008, NonZeroU8::MAX.count_bits());
268    ///
269    /// assert_eq!(016, i16::MIN.count_bits());
270    /// assert_eq!(015, i16::MAX.count_bits());
271    /// assert_eq!(016, NonZeroI16::MIN.count_bits());
272    /// assert_eq!(015, NonZeroI16::MAX.count_bits());
273    ///
274    /// assert_eq!(001, u16::MIN.count_bits());
275    /// assert_eq!(016, u16::MAX.count_bits());
276    /// assert_eq!(001, NonZeroU16::MIN.count_bits());
277    /// assert_eq!(016, NonZeroU16::MAX.count_bits());
278    ///
279    /// assert_eq!(032, i32::MIN.count_bits());
280    /// assert_eq!(031, i32::MAX.count_bits());
281    /// assert_eq!(032, NonZeroI32::MIN.count_bits());
282    /// assert_eq!(031, NonZeroI32::MAX.count_bits());
283    ///
284    /// assert_eq!(001, u32::MIN.count_bits());
285    /// assert_eq!(032, u32::MAX.count_bits());
286    /// assert_eq!(001, NonZeroU32::MIN.count_bits());
287    /// assert_eq!(032, NonZeroU32::MAX.count_bits());
288    ///
289    /// assert_eq!(064, i64::MIN.count_bits());
290    /// assert_eq!(063, i64::MAX.count_bits());
291    /// assert_eq!(064, NonZeroI64::MIN.count_bits());
292    /// assert_eq!(063, NonZeroI64::MAX.count_bits());
293    ///
294    /// assert_eq!(001, u64::MIN.count_bits());
295    /// assert_eq!(064, u64::MAX.count_bits());
296    /// assert_eq!(001, NonZeroU64::MIN.count_bits());
297    /// assert_eq!(064, NonZeroU64::MAX.count_bits());
298    ///
299    /// assert_eq!(128, i128::MIN.count_bits());
300    /// assert_eq!(127, i128::MAX.count_bits());
301    /// assert_eq!(128, NonZeroI128::MIN.count_bits());
302    /// assert_eq!(127, NonZeroI128::MAX.count_bits());
303    ///
304    /// assert_eq!(001, u128::MIN.count_bits());
305    /// assert_eq!(128, u128::MAX.count_bits());
306    /// assert_eq!(001, NonZeroU128::MIN.count_bits());
307    /// assert_eq!(128, NonZeroU128::MAX.count_bits());
308    ///
309    /// #[cfg(target_pointer_width = "64")] {
310    ///   assert_eq!(isize::MIN.count_bits(), i64::MIN.count_bits());
311    ///   assert_eq!(isize::MAX.count_bits(), i64::MAX.count_bits());
312    ///   assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI64::MIN.count_bits());
313    ///   assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI64::MAX.count_bits());
314    ///
315    ///   assert_eq!(usize::MIN.count_bits(), u64::MIN.count_bits());
316    ///   assert_eq!(usize::MAX.count_bits(), u64::MAX.count_bits());
317    ///   assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU64::MIN.count_bits());
318    ///   assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU64::MAX.count_bits());
319    /// }
320    ///
321    /// #[cfg(target_pointer_width = "32")] {
322    ///   assert_eq!(isize::MIN.count_bits(), i32::MIN.count_bits());
323    ///   assert_eq!(isize::MAX.count_bits(), i32::MAX.count_bits());
324    ///   assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI32::MIN.count_bits());
325    ///   assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI32::MAX.count_bits());
326    ///
327    ///   assert_eq!(usize::MIN.count_bits(), u32::MIN.count_bits());
328    ///   assert_eq!(usize::MAX.count_bits(), u32::MAX.count_bits());
329    ///   assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU32::MIN.count_bits());
330    ///   assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU32::MAX.count_bits());
331    /// }
332    ///
333    /// #[cfg(target_pointer_width = "16")] {
334    ///   assert_eq!(isize::MIN.count_bits(), i16::MIN.count_bits());
335    ///   assert_eq!(isize::MAX.count_bits(), i16::MAX.count_bits());
336    ///   assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI16::MIN.count_bits());
337    ///   assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI16::MAX.count_bits());
338    ///
339    ///   assert_eq!(usize::MIN.count_bits(), u16::MIN.count_bits());
340    ///   assert_eq!(usize::MAX.count_bits(), u16::MAX.count_bits());
341    ///   assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU16::MIN.count_bits());
342    ///   assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU16::MAX.count_bits());
343    /// }
344    ///
345    /// #[cfg(target_pointer_width = "8")] {
346    ///   assert_eq!(isize::MIN.count_bits(), i8::MIN.count_bits());
347    ///   assert_eq!(isize::MAX.count_bits(), i8::MAX.count_bits());
348    ///   assert_eq!(NonZeroIsize::MIN.count_bits(), NonZeroI8::MIN.count_bits());
349    ///   assert_eq!(NonZeroIsize::MAX.count_bits(), NonZeroI8::MAX.count_bits());
350    ///
351    ///   assert_eq!(usize::MIN.count_bits(), u8::MIN.count_bits());
352    ///   assert_eq!(usize::MAX.count_bits(), u8::MAX.count_bits());
353    ///   assert_eq!(NonZeroUsize::MIN.count_bits(), NonZeroU8::MIN.count_bits());
354    ///   assert_eq!(NonZeroUsize::MAX.count_bits(), NonZeroU8::MAX.count_bits());
355    /// }
356    /// ```
357    fn count_bits(self) -> u32;
358
359    /// Returns the count of octal digits in an integer.
360    ///
361    /// # Examples
362    ///
363    /// ```rust
364    /// use count_digits::CountDigits;
365    /// # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
366    /// # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
367    ///
368    /// assert_eq!(03, i8::MIN.count_octal_digits());
369    /// assert_eq!(03, i8::MAX.count_octal_digits());
370    /// assert_eq!(03, NonZeroI8::MIN.count_octal_digits());
371    /// assert_eq!(03, NonZeroI8::MAX.count_octal_digits());
372    ///
373    /// assert_eq!(01, u8::MIN.count_octal_digits());
374    /// assert_eq!(03, u8::MAX.count_octal_digits());
375    /// assert_eq!(01, NonZeroU8::MIN.count_octal_digits());
376    /// assert_eq!(03, NonZeroU8::MAX.count_octal_digits());
377    ///
378    /// assert_eq!(06, i16::MIN.count_octal_digits());
379    /// assert_eq!(05, i16::MAX.count_octal_digits());
380    /// assert_eq!(06, NonZeroI16::MIN.count_octal_digits());
381    /// assert_eq!(05, NonZeroI16::MAX.count_octal_digits());
382    ///
383    /// assert_eq!(01, u16::MIN.count_octal_digits());
384    /// assert_eq!(06, u16::MAX.count_octal_digits());
385    /// assert_eq!(01, NonZeroU16::MIN.count_octal_digits());
386    /// assert_eq!(06, NonZeroU16::MAX.count_octal_digits());
387    ///
388    /// assert_eq!(11, i32::MIN.count_octal_digits());
389    /// assert_eq!(11, i32::MAX.count_octal_digits());
390    /// assert_eq!(11, NonZeroI32::MIN.count_octal_digits());
391    /// assert_eq!(11, NonZeroI32::MAX.count_octal_digits());
392    ///
393    /// assert_eq!(01, u32::MIN.count_octal_digits());
394    /// assert_eq!(11, u32::MAX.count_octal_digits());
395    /// assert_eq!(01, NonZeroU32::MIN.count_octal_digits());
396    /// assert_eq!(11, NonZeroU32::MAX.count_octal_digits());
397    ///
398    /// assert_eq!(22, i64::MIN.count_octal_digits());
399    /// assert_eq!(21, i64::MAX.count_octal_digits());
400    /// assert_eq!(22, NonZeroI64::MIN.count_octal_digits());
401    /// assert_eq!(21, NonZeroI64::MAX.count_octal_digits());
402    ///
403    /// assert_eq!(01, u64::MIN.count_octal_digits());
404    /// assert_eq!(22, u64::MAX.count_octal_digits());
405    /// assert_eq!(01, NonZeroU64::MIN.count_octal_digits());
406    /// assert_eq!(22, NonZeroU64::MAX.count_octal_digits());
407    ///
408    /// assert_eq!(43, i128::MIN.count_octal_digits());
409    /// assert_eq!(43, i128::MAX.count_octal_digits());
410    /// assert_eq!(43, NonZeroI128::MIN.count_octal_digits());
411    /// assert_eq!(43, NonZeroI128::MAX.count_octal_digits());
412    ///
413    /// assert_eq!(01, u128::MIN.count_octal_digits());
414    /// assert_eq!(43, u128::MAX.count_octal_digits());
415    /// assert_eq!(01, NonZeroU128::MIN.count_octal_digits());
416    /// assert_eq!(43, NonZeroU128::MAX.count_octal_digits());
417    ///
418    /// #[cfg(target_pointer_width = "64")] {
419    ///   assert_eq!(isize::MIN.count_octal_digits(), i64::MIN.count_octal_digits());
420    ///   assert_eq!(isize::MAX.count_octal_digits(), i64::MAX.count_octal_digits());
421    ///   assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI64::MIN.count_octal_digits());
422    ///   assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI64::MAX.count_octal_digits());
423    ///
424    ///   assert_eq!(usize::MIN.count_octal_digits(), u64::MIN.count_octal_digits());
425    ///   assert_eq!(usize::MAX.count_octal_digits(), u64::MAX.count_octal_digits());
426    ///   assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU64::MIN.count_octal_digits());
427    ///   assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU64::MAX.count_octal_digits());
428    /// }
429    ///
430    /// #[cfg(target_pointer_width = "32")] {
431    ///   assert_eq!(isize::MIN.count_octal_digits(), i32::MIN.count_octal_digits());
432    ///   assert_eq!(isize::MAX.count_octal_digits(), i32::MAX.count_octal_digits());
433    ///   assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI32::MIN.count_octal_digits());
434    ///   assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI32::MAX.count_octal_digits());
435    ///
436    ///   assert_eq!(usize::MIN.count_octal_digits(), u32::MIN.count_octal_digits());
437    ///   assert_eq!(usize::MAX.count_octal_digits(), u32::MAX.count_octal_digits());
438    ///   assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU32::MIN.count_octal_digits());
439    ///   assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU32::MAX.count_octal_digits());
440    /// }
441    ///
442    /// #[cfg(target_pointer_width = "16")] {
443    ///   assert_eq!(isize::MIN.count_octal_digits(), i16::MIN.count_octal_digits());
444    ///   assert_eq!(isize::MAX.count_octal_digits(), i16::MAX.count_octal_digits());
445    ///   assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI16::MIN.count_octal_digits());
446    ///   assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI16::MAX.count_octal_digits());
447    ///
448    ///   assert_eq!(usize::MIN.count_octal_digits(), u16::MIN.count_octal_digits());
449    ///   assert_eq!(usize::MAX.count_octal_digits(), u16::MAX.count_octal_digits());
450    ///   assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU16::MIN.count_octal_digits());
451    ///   assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU16::MAX.count_octal_digits());
452    /// }
453    ///
454    /// #[cfg(target_pointer_width = "8")] {
455    ///   assert_eq!(isize::MIN.count_octal_digits(), i8::MIN.count_octal_digits());
456    ///   assert_eq!(isize::MAX.count_octal_digits(), i8::MAX.count_octal_digits());
457    ///   assert_eq!(NonZeroIsize::MIN.count_octal_digits(), NonZeroI8::MIN.count_octal_digits());
458    ///   assert_eq!(NonZeroIsize::MAX.count_octal_digits(), NonZeroI8::MAX.count_octal_digits());
459    ///
460    ///   assert_eq!(usize::MIN.count_octal_digits(), u8::MIN.count_octal_digits());
461    ///   assert_eq!(usize::MAX.count_octal_digits(), u8::MAX.count_octal_digits());
462    ///   assert_eq!(NonZeroUsize::MIN.count_octal_digits(), NonZeroU8::MIN.count_octal_digits());
463    ///   assert_eq!(NonZeroUsize::MAX.count_octal_digits(), NonZeroU8::MAX.count_octal_digits());
464    /// }
465    /// ```
466    fn count_octal_digits(self) -> u32;
467
468    /// Returns the count of hexadecimal digits in an integer.
469    ///
470    /// # Examples
471    ///
472    /// ```rust
473    /// use count_digits::CountDigits;
474    /// # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
475    /// # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
476    ///
477    /// assert_eq!(02, i8::MIN.count_hex_digits());
478    /// assert_eq!(02, i8::MAX.count_hex_digits());
479    /// assert_eq!(02, NonZeroI8::MIN.count_hex_digits());
480    /// assert_eq!(02, NonZeroI8::MAX.count_hex_digits());
481    ///
482    /// assert_eq!(01, u8::MIN.count_hex_digits());
483    /// assert_eq!(02, u8::MAX.count_hex_digits());
484    /// assert_eq!(01, NonZeroU8::MIN.count_hex_digits());
485    /// assert_eq!(02, NonZeroU8::MAX.count_hex_digits());
486    ///
487    /// assert_eq!(04, i16::MIN.count_hex_digits());
488    /// assert_eq!(04, i16::MAX.count_hex_digits());
489    /// assert_eq!(04, NonZeroI16::MIN.count_hex_digits());
490    /// assert_eq!(04, NonZeroI16::MAX.count_hex_digits());
491    ///
492    /// assert_eq!(01, u16::MIN.count_hex_digits());
493    /// assert_eq!(04, u16::MAX.count_hex_digits());
494    /// assert_eq!(01, NonZeroU16::MIN.count_hex_digits());
495    /// assert_eq!(04, NonZeroU16::MAX.count_hex_digits());
496    ///
497    /// assert_eq!(08, i32::MIN.count_hex_digits());
498    /// assert_eq!(08, i32::MAX.count_hex_digits());
499    /// assert_eq!(08, NonZeroI32::MIN.count_hex_digits());
500    /// assert_eq!(08, NonZeroI32::MAX.count_hex_digits());
501    ///
502    /// assert_eq!(01, u32::MIN.count_hex_digits());
503    /// assert_eq!(08, u32::MAX.count_hex_digits());
504    /// assert_eq!(01, NonZeroU32::MIN.count_hex_digits());
505    /// assert_eq!(08, NonZeroU32::MAX.count_hex_digits());
506    ///
507    /// assert_eq!(16, i64::MIN.count_hex_digits());
508    /// assert_eq!(16, i64::MAX.count_hex_digits());
509    /// assert_eq!(16, NonZeroI64::MIN.count_hex_digits());
510    /// assert_eq!(16, NonZeroI64::MAX.count_hex_digits());
511    ///
512    /// assert_eq!(01, u64::MIN.count_hex_digits());
513    /// assert_eq!(16, u64::MAX.count_hex_digits());
514    /// assert_eq!(01, NonZeroU64::MIN.count_hex_digits());
515    /// assert_eq!(16, NonZeroU64::MAX.count_hex_digits());
516    ///
517    /// assert_eq!(32, i128::MIN.count_hex_digits());
518    /// assert_eq!(32, i128::MAX.count_hex_digits());
519    /// assert_eq!(32, NonZeroI128::MIN.count_hex_digits());
520    /// assert_eq!(32, NonZeroI128::MAX.count_hex_digits());
521    ///
522    /// assert_eq!(01, u128::MIN.count_hex_digits());
523    /// assert_eq!(32, u128::MAX.count_hex_digits());
524    /// assert_eq!(01, NonZeroU128::MIN.count_hex_digits());
525    /// assert_eq!(32, NonZeroU128::MAX.count_hex_digits());
526    ///
527    /// #[cfg(target_pointer_width = "64")] {
528    ///   assert_eq!(isize::MIN.count_hex_digits(), i64::MIN.count_hex_digits());
529    ///   assert_eq!(isize::MAX.count_hex_digits(), i64::MAX.count_hex_digits());
530    ///   assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI64::MIN.count_hex_digits());
531    ///   assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI64::MAX.count_hex_digits());
532    ///
533    ///   assert_eq!(usize::MIN.count_hex_digits(), u64::MIN.count_hex_digits());
534    ///   assert_eq!(usize::MAX.count_hex_digits(), u64::MAX.count_hex_digits());
535    ///   assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU64::MIN.count_hex_digits());
536    ///   assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU64::MAX.count_hex_digits());
537    /// }
538    ///
539    /// #[cfg(target_pointer_width = "32")] {
540    ///   assert_eq!(isize::MIN.count_hex_digits(), i32::MIN.count_hex_digits());
541    ///   assert_eq!(isize::MAX.count_hex_digits(), i32::MAX.count_hex_digits());
542    ///   assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI32::MIN.count_hex_digits());
543    ///   assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI32::MAX.count_hex_digits());
544    ///
545    ///   assert_eq!(usize::MIN.count_hex_digits(), u32::MIN.count_hex_digits());
546    ///   assert_eq!(usize::MAX.count_hex_digits(), u32::MAX.count_hex_digits());
547    ///   assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU32::MIN.count_hex_digits());
548    ///   assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU32::MAX.count_hex_digits());
549    /// }
550    ///
551    /// #[cfg(target_pointer_width = "16")] {
552    ///   assert_eq!(isize::MIN.count_hex_digits(), i16::MIN.count_hex_digits());
553    ///   assert_eq!(isize::MAX.count_hex_digits(), i16::MAX.count_hex_digits());
554    ///   assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI16::MIN.count_hex_digits());
555    ///   assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI16::MAX.count_hex_digits());
556    ///
557    ///   assert_eq!(usize::MIN.count_hex_digits(), u16::MIN.count_hex_digits());
558    ///   assert_eq!(usize::MAX.count_hex_digits(), u16::MAX.count_hex_digits());
559    ///   assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU16::MIN.count_hex_digits());
560    ///   assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU16::MAX.count_hex_digits());
561    /// }
562    ///
563    /// #[cfg(target_pointer_width = "8")] {
564    ///   assert_eq!(isize::MIN.count_hex_digits(), i8::MIN.count_hex_digits());
565    ///   assert_eq!(isize::MAX.count_hex_digits(), i8::MAX.count_hex_digits());
566    ///   assert_eq!(NonZeroIsize::MIN.count_hex_digits(), NonZeroI8::MIN.count_hex_digits());
567    ///   assert_eq!(NonZeroIsize::MAX.count_hex_digits(), NonZeroI8::MAX.count_hex_digits());
568    ///
569    ///   assert_eq!(usize::MIN.count_hex_digits(), u8::MIN.count_hex_digits());
570    ///   assert_eq!(usize::MAX.count_hex_digits(), u8::MAX.count_hex_digits());
571    ///   assert_eq!(NonZeroUsize::MIN.count_hex_digits(), NonZeroU8::MIN.count_hex_digits());
572    ///   assert_eq!(NonZeroUsize::MAX.count_hex_digits(), NonZeroU8::MAX.count_hex_digits());
573    /// }
574    /// ```
575    fn count_hex_digits(self) -> u32;
576
577    /// Returns the count of decimal digits in an integer.
578    ///
579    /// <div class="warning" style="text-align: left;">
580    /// Does not count the negative sign when counting negative, signed integers because the negative sign is not a digit.
581    /// </div>
582    ///
583    /// # Examples
584    ///
585    /// ```rust
586    /// use count_digits::CountDigits;
587    /// # use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
588    /// # use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
589    ///
590    /// assert_eq!(03, i8::MIN.count_digits());
591    /// assert_eq!(03, i8::MAX.count_digits());
592    /// assert_eq!(03, NonZeroI8::MIN.count_digits());
593    /// assert_eq!(03, NonZeroI8::MAX.count_digits());
594    ///
595    /// assert_eq!(01, u8::MIN.count_digits());
596    /// assert_eq!(03, u8::MAX.count_digits());
597    /// assert_eq!(01, NonZeroU8::MIN.count_digits());
598    /// assert_eq!(03, NonZeroU8::MAX.count_digits());
599    ///
600    /// assert_eq!(05, i16::MIN.count_digits());
601    /// assert_eq!(05, i16::MAX.count_digits());
602    /// assert_eq!(05, NonZeroI16::MIN.count_digits());
603    /// assert_eq!(05, NonZeroI16::MAX.count_digits());
604    ///
605    /// assert_eq!(01, u16::MIN.count_digits());
606    /// assert_eq!(05, u16::MAX.count_digits());
607    /// assert_eq!(01, NonZeroU16::MIN.count_digits());
608    /// assert_eq!(05, NonZeroU16::MAX.count_digits());
609    ///
610    /// assert_eq!(10, i32::MIN.count_digits());
611    /// assert_eq!(10, i32::MAX.count_digits());
612    /// assert_eq!(10, NonZeroI32::MIN.count_digits());
613    /// assert_eq!(10, NonZeroI32::MAX.count_digits());
614    ///
615    /// assert_eq!(01, u32::MIN.count_digits());
616    /// assert_eq!(10, u32::MAX.count_digits());
617    /// assert_eq!(01, NonZeroU32::MIN.count_digits());
618    /// assert_eq!(10, NonZeroU32::MAX.count_digits());
619    ///
620    /// assert_eq!(19, i64::MIN.count_digits());
621    /// assert_eq!(19, i64::MAX.count_digits());
622    /// assert_eq!(19, NonZeroI64::MIN.count_digits());
623    /// assert_eq!(19, NonZeroI64::MAX.count_digits());
624    ///
625    /// assert_eq!(01, u64::MIN.count_digits());
626    /// assert_eq!(20, u64::MAX.count_digits());
627    /// assert_eq!(01, NonZeroU64::MIN.count_digits());
628    /// assert_eq!(20, NonZeroU64::MAX.count_digits());
629    ///
630    /// assert_eq!(39, i128::MIN.count_digits());
631    /// assert_eq!(39, i128::MAX.count_digits());
632    /// assert_eq!(39, NonZeroI128::MIN.count_digits());
633    /// assert_eq!(39, NonZeroI128::MAX.count_digits());
634    ///
635    /// assert_eq!(01, u128::MIN.count_digits());
636    /// assert_eq!(39, u128::MAX.count_digits());
637    /// assert_eq!(01, NonZeroU128::MIN.count_digits());
638    /// assert_eq!(39, NonZeroU128::MAX.count_digits());
639    ///
640    /// #[cfg(target_pointer_width = "64")] {
641    ///   assert_eq!(isize::MIN.count_digits(), i64::MIN.count_digits());
642    ///   assert_eq!(isize::MAX.count_digits(), i64::MAX.count_digits());
643    ///   assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI64::MIN.count_digits());
644    ///   assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI64::MAX.count_digits());
645    ///
646    ///   assert_eq!(usize::MIN.count_digits(), u64::MIN.count_digits());
647    ///   assert_eq!(usize::MAX.count_digits(), u64::MAX.count_digits());
648    ///   assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU64::MIN.count_digits());
649    ///   assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU64::MAX.count_digits());
650    /// }
651    ///
652    /// #[cfg(target_pointer_width = "32")] {
653    ///   assert_eq!(isize::MIN.count_digits(), i32::MIN.count_digits());
654    ///   assert_eq!(isize::MAX.count_digits(), i32::MAX.count_digits());
655    ///   assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI32::MIN.count_digits());
656    ///   assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI32::MAX.count_digits());
657    ///
658    ///   assert_eq!(usize::MIN.count_digits(), u32::MIN.count_digits());
659    ///   assert_eq!(usize::MAX.count_digits(), u32::MAX.count_digits());
660    ///   assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU32::MIN.count_digits());
661    ///   assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU32::MAX.count_digits());
662    /// }
663    ///
664    /// #[cfg(target_pointer_width = "16")] {
665    ///   assert_eq!(isize::MIN.count_digits(), i16::MIN.count_digits());
666    ///   assert_eq!(isize::MAX.count_digits(), i16::MAX.count_digits());
667    ///   assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI16::MIN.count_digits());
668    ///   assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI16::MAX.count_digits());
669    ///
670    ///   assert_eq!(usize::MIN.count_digits(), u16::MIN.count_digits());
671    ///   assert_eq!(usize::MAX.count_digits(), u16::MAX.count_digits());
672    ///   assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU16::MIN.count_digits());
673    ///   assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU16::MAX.count_digits());
674    /// }
675    ///
676    /// #[cfg(target_pointer_width = "8")] {
677    ///   assert_eq!(isize::MIN.count_digits(), i8::MIN.count_digits());
678    ///   assert_eq!(isize::MAX.count_digits(), i8::MAX.count_digits());
679    ///   assert_eq!(NonZeroIsize::MIN.count_digits(), NonZeroI8::MIN.count_digits());
680    ///   assert_eq!(NonZeroIsize::MAX.count_digits(), NonZeroI8::MAX.count_digits());
681    ///
682    ///   assert_eq!(usize::MIN.count_digits(), u8::MIN.count_digits());
683    ///   assert_eq!(usize::MAX.count_digits(), u8::MAX.count_digits());
684    ///   assert_eq!(NonZeroUsize::MIN.count_digits(), NonZeroU8::MIN.count_digits());
685    ///   assert_eq!(NonZeroUsize::MAX.count_digits(), NonZeroU8::MAX.count_digits());
686    /// }
687    /// ```
688    fn count_digits(self) -> usize;
689
690    /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
691    ///
692    /// [Panics](panic) if the provided radix is 0 or 1.
693    ///
694    /// See [checked_count_digits_radix()](CountDigits::checked_count_digits_radix) for a non-panicking version of this function.
695    ///
696    /// <div class="warning" style="text-align: left;">
697    /// For radix 10, does not count the negative sign when counting negative, signed integers because the negative sign is not a digit.
698    ///
699    /// For all other radix values, counts digits according to the
700    /// <a href="https://en.wikipedia.org/wiki/Two%27s_complement">twos-complement</a> representation.
701    /// </div>
702    ///
703    /// # Examples
704    ///
705    /// ```rust
706    /// use count_digits::CountDigits;
707    ///
708    /// for n in 0..100 {
709    ///   assert!(std::panic::catch_unwind(|| n.count_digits_radix(0_u32)).is_err());
710    ///   assert!(std::panic::catch_unwind(|| n.count_digits_radix(1_u32)).is_err());
711    ///
712    ///   assert_eq!(n.count_digits_radix(02_u32) as u32, n.count_bits());
713    ///   assert_eq!(n.count_digits_radix(08_u32) as u32, n.count_octal_digits());
714    ///   assert_eq!(n.count_digits_radix(16_u32) as u32, n.count_hex_digits());
715    ///   assert_eq!(n.count_digits_radix(10_u32), n.count_digits());
716    /// }
717    /// ```
718    fn count_digits_radix(self, radix: Self::Radix) -> usize;
719
720    /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
721    ///
722    /// Returns [None] if the provided radix is 0 or 1.
723    ///
724    /// See [count_digits_radix()](CountDigits::count_digits_radix) for a panicking version of this function.
725    ///
726    /// <div class="warning" style="text-align: left;">
727    /// For radix 10, does not count the negative sign when counting negative, signed integers because the negative sign is not a digit.
728    ///
729    /// For all other radix values, counts digits according to the
730    /// <a href="https://en.wikipedia.org/wiki/Two%27s_complement">twos-complement</a> representation.
731    /// </div>
732    ///
733    /// # Examples
734    ///
735    /// ```rust
736    /// use count_digits::CountDigits;
737    ///
738    /// for n in 0..100 {
739    ///   assert_eq!(n.checked_count_digits_radix(00_u32), None);
740    ///   assert_eq!(n.checked_count_digits_radix(01_u32), None);
741    ///   assert_eq!(n.checked_count_digits_radix(02_u32).unwrap() as u32, n.count_bits());
742    ///   assert_eq!(n.checked_count_digits_radix(08_u32).unwrap() as u32, n.count_octal_digits());
743    ///   assert_eq!(n.checked_count_digits_radix(16_u32).unwrap() as u32, n.count_hex_digits());
744    ///   assert_eq!(n.checked_count_digits_radix(10_u32).unwrap(), n.count_digits());
745    /// }
746    /// ```
747    fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize>;
748}
749
750macro_rules! impl_count_digits {
751    (
752        primitive_type = $primitive_type:ty,
753        non_zero_type = $non_zero_type:ty,
754        radix_type = $radix_type:ty,
755        min_value_bits = $min_value_bits:expr,
756        min_value_octal_digits = $min_value_octal_digits:expr,
757        min_value_hex_digits = $min_value_hex_digits:expr $(,)?
758    ) => {
759        impl CountDigits for $primitive_type {
760            type Radix = $radix_type;
761
762            #[inline(always)]
763            /// Returns the count of bits in an integer.
764            fn count_bits(self) -> u32 {
765                if self.is_negative() {
766                    $min_value_bits
767                } else {
768                    1 + self.checked_ilog2().unwrap_or_default()
769                }
770            }
771
772            #[inline(always)]
773            /// Returns the count of octal digits in an integer.
774            fn count_octal_digits(self) -> u32 {
775                if self.is_negative() {
776                    $min_value_octal_digits
777                } else {
778                    1 + self.checked_ilog2().unwrap_or_default() / 3
779                }
780            }
781
782            #[inline(always)]
783            /// Returns the count of hexadecimal digits in an integer.
784            fn count_hex_digits(self) -> u32 {
785                if self.is_negative() {
786                    $min_value_hex_digits
787                } else {
788                    1 + self.checked_ilog2().unwrap_or_default() / 4
789                }
790            }
791
792            #[inline(always)]
793            /// Returns the count of decimal digits in an integer.
794            fn count_digits(self) -> usize {
795                1 + self.abs_diff(0).checked_ilog10().unwrap_or_default() as usize
796            }
797
798            #[inline(always)]
799            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
800            ///
801            /// [Panics](panic) if the provided radix is 0 or 1.
802            ///
803            /// See [checked_count_digits_radix()](CountDigits::checked_count_digits_radix) for a non-panicking version of this function.
804            fn count_digits_radix(self, radix: Self::Radix) -> usize {
805                match radix {
806                    0 | 1 => panic!("base of integer logarithm must be at least 2"),
807                    02 => self.count_bits() as usize,
808                    08 => self.count_octal_digits() as usize,
809                    10 => self.count_digits(),
810                    16 => self.count_hex_digits() as usize,
811                    __ => {
812                        if self.is_negative() {
813                            1 + <$primitive_type>::MIN.abs_diff(0).ilog(radix) as usize
814                        } else {
815                            1 + self.abs_diff(0).checked_ilog(radix).unwrap_or_default() as usize
816                        }
817                    }
818                }
819            }
820
821            #[inline(always)]
822            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
823            ///
824            /// Returns [None] if the provided radix is 0 or 1.
825            ///
826            /// See [count_digits_radix()](CountDigits::count_digits_radix) for a panicking version of this function.
827            fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
828                match radix {
829                    0 | 1 => None,
830                    radix => Some(self.count_digits_radix(radix)),
831                }
832            }
833        }
834
835        impl CountDigits for $non_zero_type {
836            type Radix = $radix_type;
837
838            #[inline(always)]
839            /// Returns the count of bits in an integer.
840            fn count_bits(self) -> u32 {
841                if self.is_negative() {
842                    $min_value_bits
843                } else {
844                    1 + self.get().ilog2()
845                }
846            }
847
848            #[inline(always)]
849            /// Returns the count of octal digits in an integer.
850            fn count_octal_digits(self) -> u32 {
851                if self.is_negative() {
852                    $min_value_octal_digits
853                } else {
854                    1 + self.get().ilog2() / 3
855                }
856            }
857
858            #[inline(always)]
859            /// Returns the count of hexadecimal digits in an integer.
860            fn count_hex_digits(self) -> u32 {
861                if self.is_negative() {
862                    $min_value_hex_digits
863                } else {
864                    1 + self.get().ilog2() / 4
865                }
866            }
867
868            #[inline(always)]
869            /// Returns the count of decimal digits in an integer.
870            fn count_digits(self) -> usize {
871                1 + self.get().abs_diff(0).ilog10() as usize
872            }
873
874            #[inline(always)]
875            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
876            ///
877            /// [Panics](panic) if the provided radix is 0 or 1.
878            ///
879            /// See [checked_count_digits_radix()](CountDigits::checked_count_digits_radix) for a non-panicking version of this function.
880            fn count_digits_radix(self, radix: Self::Radix) -> usize {
881                match radix {
882                    0 | 1 => panic!("base of integer logarithm must be at least 2"),
883                    02 => self.count_bits() as usize,
884                    08 => self.count_octal_digits() as usize,
885                    10 => self.count_digits(),
886                    16 => self.count_hex_digits() as usize,
887                    __ => {
888                        if self.is_negative() {
889                            1 + <$primitive_type>::MIN.abs_diff(0).ilog(radix) as usize
890                        } else {
891                            1 + self.get().abs_diff(0).ilog(radix) as usize
892                        }
893                    }
894                }
895            }
896
897            #[inline(always)]
898            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
899            ///
900            /// Returns [None] if the provided radix is 0 or 1.
901            ///
902            /// See [count_digits_radix()](CountDigits::count_digits_radix) for a panicking version of this function.
903            fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
904                match radix {
905                    0 | 1 => None,
906                    radix => Some(self.count_digits_radix(radix)),
907                }
908            }
909        }
910    };
911    (
912        primitive_type = $primitive_type:ty,
913        non_zero_type = $non_zero_type:ty,
914    ) => {
915        impl CountDigits for $primitive_type {
916            type Radix = $primitive_type;
917
918            #[inline(always)]
919            /// Returns the count of bits in an integer.
920            fn count_bits(self) -> u32 {
921                1 + self.checked_ilog2().unwrap_or_default()
922            }
923
924            #[inline(always)]
925            /// Returns the count of octal digits in an integer.
926            fn count_octal_digits(self) -> u32 {
927                1 + self.checked_ilog2().unwrap_or_default() / 3
928            }
929
930            #[inline(always)]
931            /// Returns the count of hexadecimal digits in an integer.
932            fn count_hex_digits(self) -> u32 {
933                1 + self.checked_ilog2().unwrap_or_default() / 4
934            }
935
936            #[inline(always)]
937            /// Returns the count of decimal digits in an integer.
938            fn count_digits(self) -> usize {
939                1 + self.checked_ilog10().unwrap_or_default() as usize
940            }
941
942            #[inline(always)]
943            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
944            ///
945            /// [Panics](panic) if the provided radix is 0 or 1.
946            ///
947            /// See [checked_count_digits_radix()](CountDigits::checked_count_digits_radix) for a non-panicking version of this function.
948            fn count_digits_radix(self, radix: Self::Radix) -> usize {
949                match radix {
950                    0 | 1 => panic!("base of integer logarithm must be at least 2"),
951                    02 => self.count_bits() as usize,
952                    08 => self.count_octal_digits() as usize,
953                    10 => self.count_digits(),
954                    16 => self.count_hex_digits() as usize,
955                    __ => 1 + self.checked_ilog(radix).unwrap_or_default() as usize,
956                }
957            }
958
959            #[inline(always)]
960            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
961            ///
962            /// Returns [None] if the provided radix is 0 or 1.
963            ///
964            /// See [count_digits_radix()](CountDigits::count_digits_radix) for a panicking version of this function.
965            fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
966                match radix {
967                    0 | 1 => None,
968                    radix => Some(self.count_digits_radix(radix)),
969                }
970            }
971        }
972
973        impl CountDigits for $non_zero_type {
974            type Radix = $primitive_type;
975
976            #[inline(always)]
977            /// Returns the count of bits in an integer.
978            fn count_bits(self) -> u32 {
979                1 + self.ilog2()
980            }
981
982            #[inline(always)]
983            /// Returns the count of octal digits in an integer.
984            fn count_octal_digits(self) -> u32 {
985                1 + self.get().ilog2() / 3
986            }
987
988            #[inline(always)]
989            /// Returns the count of hexadecimal digits in an integer.
990            fn count_hex_digits(self) -> u32 {
991                1 + self.get().ilog2() / 4
992            }
993
994            #[inline(always)]
995            /// Returns the count of decimal digits in an integer.
996            fn count_digits(self) -> usize {
997                1 + self.ilog10() as usize
998            }
999
1000            #[inline(always)]
1001            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
1002            ///
1003            /// [Panics](panic) if the provided radix is 0 or 1.
1004            ///
1005            /// See [checked_count_digits_radix()](CountDigits::checked_count_digits_radix) for a non-panicking version of this function.
1006            fn count_digits_radix(self, radix: Self::Radix) -> usize {
1007                match radix {
1008                    0 | 1 => panic!("base of integer logarithm must be at least 2"),
1009                    02 => self.count_bits() as usize,
1010                    08 => self.count_octal_digits() as usize,
1011                    10 => self.count_digits(),
1012                    16 => self.count_hex_digits() as usize,
1013                    _ => 1 + self.get().ilog(radix) as usize,
1014                }
1015            }
1016
1017            #[inline(always)]
1018            /// Returns the count of digits in an integer as interpreted with the given [radix](https://en.wikipedia.org/wiki/Radix).
1019            ///
1020            /// Returns [None] if the provided radix is 0 or 1.
1021            ///
1022            /// See [count_digits_radix()](CountDigits::count_digits_radix) for a panicking version of this function.
1023            fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
1024                match radix {
1025                    0 | 1 => None,
1026                    radix => Some(self.count_digits_radix(radix)),
1027                }
1028            }
1029        }
1030    };
1031}
1032
1033impl<T: CountDigits> CountDigits for &T {
1034    type Radix = <T as CountDigits>::Radix;
1035
1036    #[inline(always)]
1037    /// Calls [count_bits()][CountDigits::count_bits] on the inner value.
1038    fn count_bits(self) -> u32 {
1039        (*self).count_bits()
1040    }
1041
1042    #[inline(always)]
1043    /// Calls [count_octal_digits()][CountDigits::count_octal_digits] on the inner value.
1044    fn count_octal_digits(self) -> u32 {
1045        (*self).count_octal_digits()
1046    }
1047
1048    #[inline(always)]
1049    /// Calls [count_digits()][CountDigits::count_digits] on the inner value.
1050    fn count_digits(self) -> usize {
1051        (*self).count_digits()
1052    }
1053
1054    #[inline(always)]
1055    /// Calls [count_hex_digits()][CountDigits::count_hex_digits] on the inner value.
1056    fn count_hex_digits(self) -> u32 {
1057        (*self).count_hex_digits()
1058    }
1059
1060    #[inline(always)]
1061    /// Calls [count_digits_radix()][CountDigits::count_digits_radix] on the inner value.
1062    fn count_digits_radix(self, radix: Self::Radix) -> usize {
1063        (*self).count_digits_radix(radix)
1064    }
1065
1066    #[inline(always)]
1067    /// Calls [checked_count_digits_radix()][CountDigits::checked_count_digits_radix] on the inner value.
1068    fn checked_count_digits_radix(self, radix: Self::Radix) -> Option<usize> {
1069        (*self).checked_count_digits_radix(radix)
1070    }
1071}
1072
1073impl_count_digits! {
1074    primitive_type = i8,
1075    non_zero_type = NonZeroI8,
1076    radix_type = u8,
1077    min_value_bits = 8,
1078    min_value_octal_digits = 3,
1079    min_value_hex_digits = 2,
1080}
1081
1082impl_count_digits! {
1083    primitive_type = i16,
1084    non_zero_type = NonZeroI16,
1085    radix_type = u16,
1086    min_value_bits = 16,
1087    min_value_octal_digits = 6,
1088    min_value_hex_digits = 4,
1089}
1090
1091impl_count_digits! {
1092    primitive_type = i32,
1093    non_zero_type = NonZeroI32,
1094    radix_type = u32,
1095    min_value_bits = 32,
1096    min_value_octal_digits = 11,
1097    min_value_hex_digits = 8,
1098}
1099
1100impl_count_digits! {
1101    primitive_type = i64,
1102    non_zero_type = NonZeroI64,
1103    radix_type = u64,
1104    min_value_bits = 64,
1105    min_value_octal_digits = 22,
1106    min_value_hex_digits = 16,
1107}
1108
1109impl_count_digits! {
1110    primitive_type = i128,
1111    non_zero_type = NonZeroI128,
1112    radix_type = u128,
1113    min_value_bits = 128,
1114    min_value_octal_digits = 43,
1115    min_value_hex_digits = 32,
1116}
1117
1118#[cfg(target_pointer_width = "64")]
1119impl_count_digits! {
1120    primitive_type = isize,
1121    non_zero_type = NonZeroIsize,
1122    radix_type = usize,
1123    min_value_bits = 64,
1124    min_value_octal_digits = 22,
1125    min_value_hex_digits = 16,
1126}
1127
1128#[cfg(target_pointer_width = "32")]
1129impl_count_digits! {
1130    primitive_type = isize,
1131    non_zero_type = NonZeroIsize,
1132    radix_type = usize,
1133    min_value_bits = 32,
1134    min_value_octal_digits = 11,
1135    min_value_hex_digits = 8,
1136}
1137
1138#[cfg(target_pointer_width = "16")]
1139impl_count_digits! {
1140    primitive_type = isize,
1141    non_zero_type = NonZeroIsize,
1142    radix_type = usize,
1143    min_value_bits = 16,
1144    min_value_octal_digits = 6,
1145    min_value_hex_digits = 4,
1146}
1147
1148#[cfg(target_pointer_width = "8")]
1149impl_count_digits! {
1150    primitive_type = isize,
1151    non_zero_type = NonZeroIsize,
1152    radix_type = usize,
1153    min_value_bits = 8,
1154    min_value_octal_digits = 3,
1155    min_value_hex_digits = 2,
1156}
1157
1158impl_count_digits! {
1159    primitive_type = u8,
1160    non_zero_type = NonZeroU8,
1161}
1162
1163impl_count_digits! {
1164    primitive_type = u16,
1165    non_zero_type = NonZeroU16,
1166}
1167
1168impl_count_digits! {
1169    primitive_type = u32,
1170    non_zero_type = NonZeroU32,
1171}
1172
1173impl_count_digits! {
1174    primitive_type = u64,
1175    non_zero_type = NonZeroU64,
1176}
1177
1178impl_count_digits! {
1179    primitive_type = u128,
1180    non_zero_type = NonZeroU128,
1181}
1182
1183impl_count_digits! {
1184    primitive_type = usize,
1185    non_zero_type = NonZeroUsize,
1186}
1187
1188#[cfg(test)]
1189mod count_digits {
1190    use super::*;
1191    use paste::paste;
1192
1193    macro_rules! binary_string_count {
1194        ($n:expr) => {
1195            format!("{:b}", $n).len() as u32
1196        };
1197    }
1198
1199    macro_rules! octal_string_count {
1200        ($n:expr) => {
1201            format!("{:o}", $n).len() as u32
1202        };
1203    }
1204
1205    macro_rules! decimal_string_count {
1206        ($n:expr) => {{
1207            let string = format!("{}", $n);
1208            string.strip_prefix('-').unwrap_or(&string).len()
1209        }};
1210    }
1211
1212    macro_rules! hex_string_count {
1213        ($n:expr) => {
1214            format!("{:x}", $n).len() as u32
1215        };
1216    }
1217
1218    macro_rules! assert_min {
1219        ($type:ty, count_bits) => {
1220            assert_eq!(
1221                <$type>::MIN.count_bits(),
1222                binary_string_count!(<$type>::MIN)
1223            );
1224            assert_eq!(
1225                <$type>::MIN.count_digits_radix(2),
1226                binary_string_count!(<$type>::MIN) as usize,
1227            );
1228        };
1229        ($type:ty, count_octal_digits) => {
1230            assert_eq!(
1231                <$type>::MIN.count_octal_digits(),
1232                octal_string_count!(<$type>::MIN),
1233            );
1234            assert_eq!(
1235                <$type>::MIN.count_digits_radix(8),
1236                octal_string_count!(<$type>::MIN) as usize,
1237            );
1238        };
1239        ($type:ty, count_digits) => {
1240            assert_eq!(
1241                <$type>::MIN.count_digits(),
1242                decimal_string_count!(<$type>::MIN)
1243            );
1244            assert_eq!(
1245                <$type>::MIN.count_digits_radix(10),
1246                decimal_string_count!(<$type>::MIN),
1247            );
1248        };
1249        ($type:ty, count_hex_digits) => {
1250            assert_eq!(
1251                <$type>::MIN.count_hex_digits(),
1252                hex_string_count!(<$type>::MIN),
1253            );
1254            assert_eq!(
1255                <$type>::MIN.count_digits_radix(16),
1256                hex_string_count!(<$type>::MIN) as usize,
1257            );
1258        };
1259    }
1260
1261    macro_rules! assert_max {
1262        ($type:ty, count_bits) => {
1263            assert_eq!(
1264                <$type>::MAX.count_bits(),
1265                binary_string_count!(<$type>::MAX)
1266            );
1267            assert_eq!(
1268                <$type>::MAX.count_digits_radix(2),
1269                binary_string_count!(<$type>::MAX) as usize,
1270            );
1271        };
1272        ($type:ty, count_octal_digits) => {
1273            assert_eq!(
1274                <$type>::MAX.count_octal_digits(),
1275                octal_string_count!(<$type>::MAX),
1276            );
1277            assert_eq!(
1278                <$type>::MAX.count_digits_radix(8),
1279                octal_string_count!(<$type>::MAX) as usize,
1280            );
1281        };
1282        ($type:ty, count_digits) => {
1283            assert_eq!(
1284                <$type>::MAX.count_digits(),
1285                decimal_string_count!(<$type>::MAX)
1286            );
1287            assert_eq!(
1288                <$type>::MAX.count_digits_radix(10),
1289                decimal_string_count!(<$type>::MAX),
1290            );
1291        };
1292        ($type:ty, count_hex_digits) => {
1293            assert_eq!(
1294                <$type>::MAX.count_hex_digits(),
1295                hex_string_count!(<$type>::MAX),
1296            );
1297            assert_eq!(
1298                <$type>::MAX.count_digits_radix(16),
1299                hex_string_count!(<$type>::MAX) as usize,
1300            );
1301        };
1302    }
1303
1304    macro_rules! assert_representations {
1305        ($n:expr, count_bits) => {
1306            assert_eq!($n.count_bits(), binary_string_count!($n));
1307            assert_eq!($n.count_digits_radix(2), binary_string_count!($n) as usize);
1308        };
1309        ($n:expr, count_octal_digits) => {
1310            assert_eq!($n.count_octal_digits(), octal_string_count!($n));
1311            assert_eq!($n.count_digits_radix(8), octal_string_count!($n) as usize);
1312        };
1313        ($n:expr, count_digits) => {
1314            assert_eq!($n.count_digits(), decimal_string_count!($n));
1315            assert_eq!($n.count_digits_radix(10), decimal_string_count!($n));
1316        };
1317        ($n:expr, count_hex_digits) => {
1318            assert_eq!($n.count_hex_digits(), hex_string_count!($n));
1319            assert_eq!($n.count_digits_radix(16), hex_string_count!($n) as usize);
1320        };
1321        ($n:expr, count_digits_radix_ordering) => {
1322            assert!([
1323                $n.count_digits_radix(02),
1324                $n.count_digits_radix(03),
1325                $n.count_digits_radix(04),
1326                $n.count_digits_radix(05),
1327                $n.count_digits_radix(06),
1328                $n.count_digits_radix(07),
1329                $n.count_digits_radix(08),
1330                $n.count_digits_radix(09),
1331                $n.count_digits_radix(11),
1332                $n.count_digits_radix(12),
1333                $n.count_digits_radix(13),
1334                $n.count_digits_radix(14),
1335                $n.count_digits_radix(15),
1336                $n.count_digits_radix(16),
1337            ]
1338            .windows(2)
1339            .all(|window| window[0] >= window[1]));
1340        };
1341        ($n:expr, checked_count_digits_radix_ordering) => {
1342            assert!([
1343                $n.checked_count_digits_radix(02).unwrap(),
1344                $n.checked_count_digits_radix(03).unwrap(),
1345                $n.checked_count_digits_radix(04).unwrap(),
1346                $n.checked_count_digits_radix(05).unwrap(),
1347                $n.checked_count_digits_radix(06).unwrap(),
1348                $n.checked_count_digits_radix(07).unwrap(),
1349                $n.checked_count_digits_radix(08).unwrap(),
1350                $n.checked_count_digits_radix(09).unwrap(),
1351                $n.checked_count_digits_radix(11).unwrap(),
1352                $n.checked_count_digits_radix(12).unwrap(),
1353                $n.checked_count_digits_radix(13).unwrap(),
1354                $n.checked_count_digits_radix(14).unwrap(),
1355                $n.checked_count_digits_radix(15).unwrap(),
1356                $n.checked_count_digits_radix(16).unwrap(),
1357            ]
1358            .windows(2)
1359            .all(|window| window[0] >= window[1]));
1360        };
1361    }
1362
1363    macro_rules! lower_bound {
1364        ($type:ty) => {
1365            -100_000 as $type
1366        };
1367    }
1368
1369    macro_rules! upper_bound {
1370        ($type:ty) => {
1371            100_000 as $type
1372        };
1373    }
1374
1375    macro_rules! min_or_lower_bound {
1376        (i8) => {
1377            i8::MIN
1378        };
1379        (i16) => {
1380            i16::MIN
1381        };
1382        (isize) => {{
1383            #[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
1384            const fn min_or_lower_bound() -> isize {
1385                lower_bound!(isize)
1386            }
1387            #[cfg(any(target_pointer_width = "16", target_pointer_width = "8"))]
1388            const fn min_or_lower_bound() -> isize {
1389                isize::MIN
1390            }
1391            min_or_lower_bound()
1392        }};
1393        ($type:ty) => {
1394            lower_bound!($type)
1395        };
1396    }
1397
1398    macro_rules! max_or_upper_bound {
1399        (i8) => {
1400            i8::MAX
1401        };
1402        (i16) => {
1403            i16::MAX
1404        };
1405        (u8) => {
1406            u8::MAX
1407        };
1408        (u16) => {
1409            u16::MAX
1410        };
1411        (isize) => {{
1412            #[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
1413            const fn max_or_upper_bound() -> isize {
1414                upper_bound!(isize)
1415            }
1416            #[cfg(any(target_pointer_width = "16", target_pointer_width = "8"))]
1417            const fn max_or_upper_bound() -> isize {
1418                isize::MAX
1419            }
1420            max_or_upper_bound()
1421        }};
1422        (usize) => {{
1423            #[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
1424            const fn max_or_upper_bound() -> usize {
1425                upper_bound!(usize)
1426            }
1427            #[cfg(any(target_pointer_width = "16", target_pointer_width = "8"))]
1428            const fn max_or_upper_bound() -> usize {
1429                isize::MAX
1430            }
1431            max_or_upper_bound()
1432        }};
1433        ($type:ty) => {
1434            upper_bound!($type)
1435        };
1436    }
1437
1438    /// Returns an iterator over the pairs boundaries [n, m] for a given radix
1439    /// where n is the largest number of its digit-size group and m is the smallest
1440    /// number of its digit-size group.
1441    macro_rules! radix_boundaries {
1442        ($type:ty, $radix:expr) => {
1443            std::iter::successors(Some($radix as $type), move |n| {
1444                n.checked_mul($radix as $type)
1445            })
1446            .map(|n| [n - 1, n])
1447        };
1448    }
1449
1450    #[test]
1451    fn helper_radix_boundaries() {
1452        assert_eq!(
1453            radix_boundaries!(i8, 2).collect::<Vec<_>>(),
1454            [[1, 2], [3, 4], [7, 8], [15, 16], [31, 32], [63, 64]],
1455        );
1456        assert_eq!(
1457            radix_boundaries!(i16, 10).collect::<Vec<_>>(),
1458            [[9, 10], [99, 100], [999, 1000], [9999, 10000]],
1459        );
1460        assert_eq!(
1461            radix_boundaries!(i16, 16).collect::<Vec<_>>(),
1462            [[0xF, 0x10], [0xFF, 0x100], [0xFFF, 0x1000]],
1463        );
1464    }
1465
1466    /// Returns an iterator of increasing pairs staring with (1, 2).
1467    fn increasing_pairs() -> impl Iterator<Item = (usize, usize)> {
1468        std::iter::successors(Some(1usize), move |n| n.checked_add(1))
1469            .zip(std::iter::successors(Some(2usize), move |n| {
1470                n.checked_add(1)
1471            }))
1472    }
1473
1474    #[test]
1475    fn helper_increasing_pairs() {
1476        assert_eq!(
1477            increasing_pairs().take(5).collect::<Vec<_>>(),
1478            [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)],
1479        );
1480    }
1481
1482    macro_rules! min_and_max {
1483        ($type:ty, $non_zero_type:ty) => {
1484            min_and_max!($type, $non_zero_type, count_bits);
1485            min_and_max!($type, $non_zero_type, count_octal_digits);
1486            min_and_max!($type, $non_zero_type, count_digits);
1487            min_and_max!($type, $non_zero_type, count_hex_digits);
1488        };
1489        ($type:ty, $non_zero_type:ty, $function:ident) => {
1490            paste! {
1491                #[test]
1492                fn [<$type _min_ $function>]() {
1493                    assert_min!($type, $function);
1494                }
1495                #[test]
1496                fn [<$type _max_ $function>]() {
1497                    assert_max!($type, $function);
1498                }
1499
1500                #[test]
1501                #[allow(non_snake_case)]
1502                fn [<$non_zero_type _min_ $function>]() {
1503                    assert_min!($non_zero_type, $function);
1504                }
1505                #[test]
1506                #[allow(non_snake_case)]
1507                fn [<$non_zero_type _max_ $function>]() {
1508                    assert_max!($non_zero_type, $function);
1509                }
1510            }
1511        };
1512    }
1513
1514    macro_rules! iteration {
1515        ($signage:ident, $type:ty, $non_zero_type:ty) => {
1516            iteration!($signage, $type, $non_zero_type, count_bits);
1517            iteration!($signage, $type, $non_zero_type, count_octal_digits);
1518            iteration!($signage, $type, $non_zero_type, count_digits);
1519            iteration!($signage, $type, $non_zero_type, count_hex_digits);
1520            iteration!($signage, $type, $non_zero_type, count_digits_radix_ordering);
1521            iteration!(
1522                $signage,
1523                $type,
1524                $non_zero_type,
1525                checked_count_digits_radix_ordering
1526            );
1527        };
1528        (signed, $type:ty, $non_zero_type:ty, $function:ident) => {
1529            paste! {
1530                #[test]
1531                fn [<$type _iteration_ $function>]() {
1532                    let max = max_or_upper_bound!($type);
1533                    let min = min_or_lower_bound!($type);
1534                    for n in min..=max {
1535                        assert_representations!(n, $function);
1536                    }
1537                }
1538
1539                #[test]
1540                #[allow(non_snake_case)]
1541                fn [<$non_zero_type _iteration_ $function>]() {
1542                    let max = max_or_upper_bound!($type);
1543                    let min = min_or_lower_bound!($type);
1544                    for n in min..=max {
1545                        if n == 0 { continue; }
1546                        let n = $non_zero_type::new(n).unwrap();
1547                        assert_representations!(n, $function);
1548                    }
1549                }
1550            }
1551        };
1552        (unsigned, $type:ty, $non_zero_type:ty, $function:ident) => {
1553            paste! {
1554                #[test]
1555                fn [<$type _iteration_ $function>]() {
1556                    let max = max_or_upper_bound!($type);
1557                    for n in $type::MIN..=max {
1558                        assert_representations!(n, $function);
1559                    }
1560                }
1561
1562                #[test]
1563                #[allow(non_snake_case)]
1564                fn [<$non_zero_type _iteration_ $function>]() {
1565                    let max = max_or_upper_bound!($type);
1566                    for n in $non_zero_type::MIN.get()..=max {
1567                        let n = $non_zero_type::new(n).unwrap();
1568                        assert_representations!(n, $function);
1569                    }
1570                }
1571            }
1572        };
1573    }
1574
1575    macro_rules! pass_by_reference {
1576        ($type:ty, $non_zero_type:ty) => {
1577            pass_by_reference!($type, $non_zero_type, count_bits);
1578            pass_by_reference!($type, $non_zero_type, count_octal_digits);
1579            pass_by_reference!($type, $non_zero_type, count_hex_digits);
1580            pass_by_reference!($type, $non_zero_type, count_digits);
1581            pass_by_reference!($type, $non_zero_type, count_digits_radix);
1582            pass_by_reference!($type, $non_zero_type, checked_count_digits_radix);
1583        };
1584        ($type:ty, $non_zero_type:ty, count_digits_radix) => {
1585            paste! {
1586                #[test]
1587                fn [<$type _pass_by_reference_count_digits_radix>]() {
1588                    for radix in 2..20 {
1589                        for n in radix_boundaries!($type, radix).flatten() {
1590                            assert_eq!(CountDigits::count_digits_radix(n, radix), CountDigits::count_digits_radix(&n, radix));
1591                        }
1592                    }
1593                }
1594                #[test]
1595                #[allow(non_snake_case)]
1596                fn [<$non_zero_type _pass_by_reference_count_digits_radix>]() {
1597                    for radix in 2..20 {
1598                        for n in radix_boundaries!($type, radix).flatten() {
1599                            let n = $non_zero_type::new(n).unwrap();
1600                            assert_eq!(CountDigits::count_digits_radix(n, radix), CountDigits::count_digits_radix(&n, radix));
1601                        }
1602                    }
1603                }
1604            }
1605        };
1606        ($type:ty, $non_zero_type:ty, checked_count_digits_radix) => {
1607            paste! {
1608                #[test]
1609                fn [<$type _pass_by_reference_checked_count_digits_radix>]() {
1610                    for radix in 2..20 {
1611                        for n in radix_boundaries!($type, radix).flatten() {
1612                            assert_eq!(CountDigits::checked_count_digits_radix(n, radix), CountDigits::checked_count_digits_radix(&n, radix));
1613                        }
1614                    }
1615                }
1616                #[test]
1617                #[allow(non_snake_case)]
1618                fn [<$non_zero_type _pass_by_reference_checked_count_digits_radix>]() {
1619                    for radix in 2..20 {
1620                        for n in radix_boundaries!($type, radix).flatten() {
1621                            let n = $non_zero_type::new(n).unwrap();
1622                            assert_eq!(CountDigits::checked_count_digits_radix(n, radix), CountDigits::checked_count_digits_radix(&n, radix));
1623                        }
1624                    }
1625                }
1626            }
1627        };
1628        ($type:ty, $non_zero_type:ty, $function:ident) => {
1629            paste! {
1630                #[test]
1631                fn [<$type _pass_by_reference_ $function>]() {
1632                    for radix in 2..20 {
1633                        for n in radix_boundaries!($type, radix).flatten() {
1634                            assert_eq!(CountDigits::$function(n), CountDigits::$function(&n));
1635                        }
1636                    }
1637                }
1638                #[test]
1639                #[allow(non_snake_case)]
1640                fn [<$non_zero_type _pass_by_reference_ $function>]() {
1641                    for radix in 2..20 {
1642                        for n in radix_boundaries!($type, radix).flatten() {
1643                            let n = $non_zero_type::new(n).unwrap();
1644                            assert_eq!(CountDigits::$function(n), CountDigits::$function(&n));
1645                        }
1646                    }
1647                }
1648            }
1649        };
1650    }
1651
1652    macro_rules! invalid_radix {
1653        ($type:ty, $non_zero_type:ty) => {
1654            invalid_radix!(0, $type, $non_zero_type);
1655            invalid_radix!(1, $type, $non_zero_type);
1656        };
1657        ($radix:expr, $type:ty, $non_zero_type:ty) => {
1658            paste! {
1659                #[test]
1660                #[should_panic(expected = "base of integer logarithm must be at least 2")]
1661                fn [<$type _invalid_radix_ $radix>]() {
1662                    (1 as $type).count_digits_radix($radix);
1663                }
1664                #[test]
1665                fn [<$type _invalid_radix_ $radix _checked>]() {
1666                    assert!((1 as $type).checked_count_digits_radix($radix).is_none());
1667                }
1668
1669
1670                #[test]
1671                #[allow(non_snake_case)]
1672                #[should_panic(expected = "base of integer logarithm must be at least 2")]
1673                fn [<$non_zero_type _invalid_radix_ $radix>]() {
1674                    $non_zero_type::new(1).unwrap().count_digits_radix($radix);
1675                }
1676                #[test]
1677                #[allow(non_snake_case)]
1678                fn [<$non_zero_type _invalid_radix_ $radix _checked>]() {
1679                    assert!($non_zero_type::new(1).unwrap().checked_count_digits_radix($radix).is_none());
1680                }
1681            }
1682        };
1683    }
1684
1685    macro_rules! boundaries_for_radix {
1686        ($type:ty, $non_zero_type:ty) => {
1687            boundaries_for_radix!(02, $type, $non_zero_type);
1688            boundaries_for_radix!(03, $type, $non_zero_type);
1689            boundaries_for_radix!(04, $type, $non_zero_type);
1690            boundaries_for_radix!(05, $type, $non_zero_type);
1691            boundaries_for_radix!(06, $type, $non_zero_type);
1692            boundaries_for_radix!(07, $type, $non_zero_type);
1693            boundaries_for_radix!(08, $type, $non_zero_type);
1694            boundaries_for_radix!(09, $type, $non_zero_type);
1695            boundaries_for_radix!(10, $type, $non_zero_type);
1696            boundaries_for_radix!(11, $type, $non_zero_type);
1697            boundaries_for_radix!(12, $type, $non_zero_type);
1698            boundaries_for_radix!(13, $type, $non_zero_type);
1699            boundaries_for_radix!(14, $type, $non_zero_type);
1700            boundaries_for_radix!(15, $type, $non_zero_type);
1701            boundaries_for_radix!(16, $type, $non_zero_type);
1702            boundaries_for_radix!(17, $type, $non_zero_type);
1703            boundaries_for_radix!(18, $type, $non_zero_type);
1704            boundaries_for_radix!(19, $type, $non_zero_type);
1705        };
1706        ($radix:expr, $type:ty, $non_zero_type:ty) => {
1707            paste! {
1708                #[test]
1709                fn [<$type _boundaries_for_radix_ $radix>]() {
1710                    assert!(
1711                        radix_boundaries!($type, $radix)
1712                            .map(|[n, m]| (n.count_digits_radix($radix), m.count_digits_radix($radix)))
1713                            .zip(increasing_pairs())
1714                            .all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
1715                                lhs_expected == lhs_actual && rhs_expected == rhs_actual
1716                            })
1717                    )
1718                }
1719                #[test]
1720                fn [<$type _boundaries_for_radix_ $radix _checked>]() {
1721                    assert!(
1722                        radix_boundaries!($type, $radix)
1723                            .map(|[n, m]| (n.checked_count_digits_radix($radix), m.checked_count_digits_radix($radix)))
1724                            .zip(increasing_pairs())
1725                            .all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
1726                                lhs_expected == lhs_actual.unwrap() && rhs_expected == rhs_actual.unwrap()
1727                            })
1728                    )
1729                }
1730                #[test]
1731                #[allow(non_snake_case)]
1732                fn [<$non_zero_type _boundaries_for_radix_ $radix>]() {
1733                    assert!(
1734                        radix_boundaries!($type, $radix)
1735                            .map(|[n, m]| (<$non_zero_type>::new(n).unwrap(), <$non_zero_type>::new(m).unwrap()))
1736                            .map(|(n, m)| (n.count_digits_radix($radix), m.count_digits_radix($radix)))
1737                            .zip(increasing_pairs())
1738                            .all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
1739                                lhs_expected == lhs_actual && rhs_expected == rhs_actual
1740                            })
1741                    )
1742                }
1743                #[test]
1744                #[allow(non_snake_case)]
1745                fn [<$non_zero_type _boundaries_for_radix_ $radix _checked>]() {
1746                    assert!(
1747                        radix_boundaries!($type, $radix)
1748                            .map(|[n, m]| (<$non_zero_type>::new(n).unwrap(), <$non_zero_type>::new(m).unwrap()))
1749                            .map(|(n, m)| (n.checked_count_digits_radix($radix), m.checked_count_digits_radix($radix)))
1750                            .zip(increasing_pairs())
1751                            .all(|((lhs_actual, rhs_actual), (lhs_expected, rhs_expected))| {
1752                                lhs_expected == lhs_actual.unwrap() && rhs_expected == rhs_actual.unwrap()
1753                            })
1754                    )
1755                }
1756            }
1757        };
1758    }
1759
1760    macro_rules! add_test {
1761        ($name:ident, $($args:tt)+) => {
1762            $name!($($args)*);
1763        };
1764    }
1765
1766    add_test!(boundaries_for_radix, i8, NonZeroI8);
1767    add_test!(boundaries_for_radix, i16, NonZeroI16);
1768    add_test!(boundaries_for_radix, i32, NonZeroI32);
1769    add_test!(boundaries_for_radix, i64, NonZeroI64);
1770    add_test!(boundaries_for_radix, i128, NonZeroI128);
1771    add_test!(boundaries_for_radix, isize, NonZeroIsize);
1772
1773    add_test!(boundaries_for_radix, u8, NonZeroU8);
1774    add_test!(boundaries_for_radix, u16, NonZeroU16);
1775    add_test!(boundaries_for_radix, u32, NonZeroU32);
1776    add_test!(boundaries_for_radix, u64, NonZeroU64);
1777    add_test!(boundaries_for_radix, u128, NonZeroU128);
1778    add_test!(boundaries_for_radix, usize, NonZeroUsize);
1779
1780    add_test!(invalid_radix, i8, NonZeroI8);
1781    add_test!(invalid_radix, i16, NonZeroI16);
1782    add_test!(invalid_radix, i32, NonZeroI32);
1783    add_test!(invalid_radix, i64, NonZeroI64);
1784    add_test!(invalid_radix, isize, NonZeroIsize);
1785
1786    add_test!(invalid_radix, u8, NonZeroU8);
1787    add_test!(invalid_radix, u16, NonZeroU16);
1788    add_test!(invalid_radix, u32, NonZeroU32);
1789    add_test!(invalid_radix, u64, NonZeroU64);
1790    add_test!(invalid_radix, usize, NonZeroUsize);
1791
1792    add_test!(iteration, signed, i8, NonZeroI8);
1793    add_test!(iteration, signed, i16, NonZeroI16);
1794    add_test!(iteration, signed, i32, NonZeroI32);
1795    add_test!(iteration, signed, i64, NonZeroI64);
1796    add_test!(iteration, signed, i128, NonZeroI128);
1797    add_test!(iteration, signed, isize, NonZeroIsize);
1798
1799    add_test!(iteration, unsigned, u8, NonZeroU8);
1800    add_test!(iteration, unsigned, u16, NonZeroU16);
1801    add_test!(iteration, unsigned, u32, NonZeroU32);
1802    add_test!(iteration, unsigned, u64, NonZeroU64);
1803    add_test!(iteration, unsigned, u128, NonZeroU128);
1804    add_test!(iteration, unsigned, usize, NonZeroUsize);
1805
1806    add_test!(min_and_max, i8, NonZeroI8);
1807    add_test!(min_and_max, i16, NonZeroI16);
1808    add_test!(min_and_max, i32, NonZeroI32);
1809    add_test!(min_and_max, i64, NonZeroI64);
1810    add_test!(min_and_max, i128, NonZeroI128);
1811    add_test!(min_and_max, isize, NonZeroIsize);
1812
1813    add_test!(min_and_max, u8, NonZeroU8);
1814    add_test!(min_and_max, u16, NonZeroU16);
1815    add_test!(min_and_max, u32, NonZeroU32);
1816    add_test!(min_and_max, u64, NonZeroU64);
1817    add_test!(min_and_max, u128, NonZeroU128);
1818    add_test!(min_and_max, usize, NonZeroUsize);
1819
1820    add_test!(pass_by_reference, i8, NonZeroI8);
1821    add_test!(pass_by_reference, i16, NonZeroI16);
1822    add_test!(pass_by_reference, i32, NonZeroI32);
1823    add_test!(pass_by_reference, i64, NonZeroI64);
1824    add_test!(pass_by_reference, i128, NonZeroI128);
1825    add_test!(pass_by_reference, isize, NonZeroIsize);
1826    add_test!(pass_by_reference, u8, NonZeroU8);
1827    add_test!(pass_by_reference, u16, NonZeroU16);
1828    add_test!(pass_by_reference, u32, NonZeroU32);
1829    add_test!(pass_by_reference, u64, NonZeroU64);
1830    add_test!(pass_by_reference, u128, NonZeroU128);
1831    add_test!(pass_by_reference, usize, NonZeroUsize);
1832}