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}