devela/text/ascii/
wrapper.rs

1// devela::text::ascii::wrapper
2//
3//! Ascii functionality wrapper struct.
4//
5
6use crate::iif;
7
8// imports for the `digits_str` method
9#[cfg(all(feature = "_str_u8", any(feature = "safe_text", not(feature = "unsafe_str"))))]
10use crate::unwrap;
11#[cfg(all(feature = "_str_u8", feature = "_cmp_u8"))]
12use crate::Compare;
13#[cfg(feature = "_str_u8")]
14use crate::StringU8;
15
16#[doc = crate::TAG_NAMESPACE!()]
17/// Provides ASCII operations on `T`, most of them *const*.
18#[derive(Clone, Copy)]
19#[repr(transparent)]
20pub struct Ascii<T: Copy>(pub T);
21
22impl Ascii<usize> {
23    /// The maximum number of decimal digits a `usize` can represent in the current platform.
24    pub const MAX_DIGITS: usize = Ascii(usize::MAX).count_digits() as usize;
25
26    /// Returns the ASCII byte of a specific digit in a `usize` number.
27    ///
28    /// # Arguments
29    /// * `divisor`: A power of 10 used to determine which digit to extract.
30    ///
31    /// # Examples
32    /// ```
33    /// # use devela::text::Ascii;
34    /// assert_eq!(Ascii(12345_usize).calc_digit(10), b'4');
35    /// assert_eq!(Ascii(12345_usize).calc_digit(1000), b'2');
36    /// ```
37    #[must_use]
38    pub const fn calc_digit(self, divisor: usize) -> u8 {
39        (self.0 / divisor % 10) as u8 + b'0'
40    }
41
42    /// Counts the number of decimal digits.
43    ///
44    /// For more complex needs check the [`Int`][crate::Int] *base* methods.
45    /// # Examples
46    /// ```
47    /// # use devela::text::Ascii;
48    /// assert_eq![1, Ascii(0_usize).count_digits()];
49    /// assert_eq![4, Ascii(9876_usize).count_digits()];
50    /// ```
51    #[must_use]
52    pub const fn count_digits(self) -> u8 {
53        iif![self.0 == 0; 1; self.0.ilog10() as u8 + 1]
54    }
55
56    /// Converts a `usize` into a byte array of `5` ascii digits with leading zeros.
57    ///
58    /// The actual array length depends on the target platform's pointer size.
59    ///
60    /// You can trim the leading zeros with
61    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
62    #[must_use] #[cfg(target_pointer_width = "16")] #[rustfmt::skip]
63    pub const fn digits(self) -> [u8; Self::MAX_DIGITS] {
64        Ascii(self.0 as u16).digits()
65    }
66
67    /// Converts a `usize` into a byte array of `10` ascii digits with leading zeros.
68    ///
69    /// The actual array length depends on the target platform's pointer size.
70    ///
71    /// You can trim the leading zeros with
72    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
73    #[must_use] #[cfg(target_pointer_width = "32")] #[rustfmt::skip]
74    pub const fn digits(self) -> [u8; Self::MAX_DIGITS] {
75        Ascii(self.0 as u32).digits()
76    }
77
78    /// Converts a `usize` into a byte array of `20` ascii digits with leading zeros.
79    ///
80    /// The actual array length depends on the target platform's pointer size.
81    ///
82    /// You can trim the leading zeros with
83    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
84    #[must_use] #[cfg(target_pointer_width = "64")] #[rustfmt::skip]
85    pub const fn digits(self) -> [u8; Self::MAX_DIGITS] {
86        Ascii(self.0 as u64).digits()
87    }
88
89    /// Returns a static string with zero-padded digits with minimum `width`.
90    ///
91    /// The given `width` will be clamped betweeen the actual number of digits
92    /// and the maximum number of digits.
93    ///
94    /// # Features
95    /// - Will only be *const* if the `_cmp_u8` feature is enabled.
96    /// - Makes use of the `unsafe_str` feature if enabled.
97    #[cfg(feature = "_cmp_u8")] // const
98    #[cfg(feature = "_str_u8")]
99    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "string_u8")))]
100    pub const fn digits_str(self, width: u8) -> StringU8<{ Self::MAX_DIGITS }> {
101        let width = Compare(width).clamp(self.count_digits(), Self::MAX_DIGITS as u8);
102
103        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
104        return unwrap![ok StringU8::<{Self::MAX_DIGITS}>::from_bytes_nright(self.digits(), width)];
105        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
106        // SAFETY: the bytes are valid utf-8
107        unsafe {
108            StringU8::<{ Self::MAX_DIGITS }>::from_bytes_nright_unchecked(self.digits(), width)
109        }
110    }
111    #[allow(missing_docs)]
112    #[cfg(not(feature = "_cmp_u8"))] // !const
113    #[cfg(feature = "_str_u8")]
114    pub fn digits_str(self, width: u8) -> StringU8<{ Self::MAX_DIGITS }> {
115        let width = width.max(self.count_digits()).min(Self::MAX_DIGITS as u8);
116
117        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
118        return unwrap![ok StringU8::<{Self::MAX_DIGITS}>::from_bytes_nright(self.digits(), width)];
119        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
120        // SAFETY: the bytes are valid utf-8
121        unsafe {
122            StringU8::<{ Self::MAX_DIGITS }>::from_bytes_nright_unchecked(self.digits(), width)
123        }
124    }
125}
126
127impl Ascii<u8> {
128    /// The maximum number of decimal digits a `u8` can represent.
129    pub const MAX_DIGITS: usize = 3;
130
131    /// Returns the ASCII byte of a specific digit in a `u8` number.
132    ///
133    /// # Arguments
134    /// * `divisor`: A power of 10 used to determine which digit to extract.
135    ///
136    /// # Examples
137    /// ```
138    /// # use devela::text::Ascii;
139    /// assert_eq!(Ascii(123_u8).calc_digit(10), b'2');
140    /// assert_eq!(Ascii(123_u8).calc_digit(100), b'1');
141    /// ```
142    #[must_use]
143    pub const fn calc_digit(self, divisor: u8) -> u8 {
144        (self.0 / divisor % 10) + b'0'
145    }
146
147    /// Counts the number of decimal digits.
148    ///
149    /// For more complex needs check the [`Int`][crate::num::Int] *base* methods.
150    /// # Examples
151    /// ```
152    /// # use devela::text::Ascii;
153    /// assert_eq![1, Ascii(0_u8).count_digits()];
154    /// assert_eq![3, Ascii(123_u8).count_digits()];
155    /// ```
156    #[must_use]
157    pub const fn count_digits(self) -> u8 {
158        iif![self.0 == 0; 1; self.0.ilog10() as u8 + 1]
159    }
160
161    /// Converts a `u8` into a byte array of `3` ASCII digits with leading zeros.
162    ///
163    /// You can trim the leading zeros with
164    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
165    #[must_use]
166    pub const fn digits(self) -> [u8; 3] {
167        [
168            //              321
169            //              255 u8::MAX
170            self.calc_digit(100),
171            self.calc_digit(10),
172            self.calc_digit(1),
173        ]
174    }
175
176    /// Returns a static string with zero-padded digits with minimum `width`.
177    ///
178    /// The given `width` will be clamped betweeen the actual number of digits
179    /// and the maximum number of digits.
180    ///
181    /// # Features
182    /// - Will only be *const* if the `_cmp_u8` feature is enabled.
183    /// - Makes use of the `unsafe_str` feature if enabled.
184    #[cfg(feature = "_cmp_u8")] // const
185    #[cfg(feature = "_str_u8")]
186    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "string_u8")))]
187    pub const fn digits_str(self, width: u8) -> StringU8<3> {
188        let width = Compare(width).clamp(self.count_digits(), 3);
189
190        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
191        return unwrap![ok StringU8::<3>::from_bytes_nright(self.digits(), width)];
192        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
193        // SAFETY: the bytes are valid utf-8
194        unsafe {
195            StringU8::<3>::from_bytes_nright_unchecked(self.digits(), width)
196        }
197    }
198    #[allow(missing_docs)]
199    #[cfg(not(feature = "_cmp_u8"))] // !const
200    #[cfg(feature = "_str_u8")]
201    pub fn digits_str(self, width: u8) -> StringU8<3> {
202        let width = width.max(self.count_digits()).min(3);
203
204        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
205        return unwrap![ok StringU8::<3>::from_bytes_nright(self.digits(), width)];
206        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
207        // SAFETY: the bytes are valid utf-8
208        unsafe {
209            StringU8::<3>::from_bytes_nright_unchecked(self.digits(), width)
210        }
211    }
212
213    /// Converts a one-digit number to the corresponding `1` ASCII digit.
214    ///
215    /// # Panics
216    /// This function panics in debug if the given number is > 9.
217    #[must_use]
218    pub const fn digits_1(self) -> u8 {
219        debug_assert![self.0 <= 9];
220        self.0 + b'0'
221    }
222
223    /// Converts a two-digit number to the corresponding `2` ASCII digits.
224    ///
225    /// # Panics
226    /// This function panics in debug if the given number is > 99.
227    #[must_use]
228    pub const fn digits_2(self) -> [u8; 2] {
229        debug_assert![self.0 <= 99];
230        [self.calc_digit(10), self.calc_digit(1)]
231    }
232}
233
234impl Ascii<u16> {
235    /// The maximum number of decimal digits a `u16` can represent.
236    pub const MAX_DIGITS: usize = 5;
237
238    /// Returns the ASCII byte of a specific digit in a `u16` number.
239    ///
240    /// # Arguments
241    /// * `divisor`: A power of 10 used to determine which digit to extract.
242    ///
243    /// # Examples
244    /// ```
245    /// # use devela::text::Ascii;
246    /// assert_eq!(Ascii(12345_u16).calc_digit(10), b'4');
247    /// assert_eq!(Ascii(12345_u16).calc_digit(1000), b'2');
248    /// ```
249    #[must_use]
250    pub const fn calc_digit(self, divisor: u16) -> u8 {
251        (self.0 / divisor % 10) as u8 + b'0'
252    }
253
254    /// Counts the number of decimal digits.
255    ///
256    /// For more complex needs check the [`Int`][crate::num::Int] *base* methods.
257    /// # Examples
258    /// ```
259    /// # use devela::text::Ascii;
260    /// assert_eq![1, Ascii(0_u16).count_digits()];
261    /// assert_eq![4, Ascii(9876_u16).count_digits()];
262    /// ```
263    #[must_use]
264    pub const fn count_digits(self) -> u8 {
265        iif![self.0 == 0; 1; self.0.ilog10() as u8 + 1]
266    }
267
268    /// Converts a `u16` into a byte array of `5` ASCII digits with leading zeros.
269    ///
270    /// You can trim the leading zeros with
271    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
272    #[must_use]
273    pub const fn digits(self) -> [u8; 5] {
274        [
275            //              54321
276            //              65535    ← u16::MAX
277            self.calc_digit(10000), // 5 digits
278            self.calc_digit(1000),
279            self.calc_digit(100),
280            self.calc_digit(10),
281            self.calc_digit(1),
282        ]
283    }
284
285    /// Returns a static string with zero-padded digits with minimum `width`.
286    ///
287    /// The given `width` will be clamped betweeen the actual number of digits
288    /// and the maximum number of digits.
289    ///
290    /// # Features
291    /// - Will only be *const* if the `_cmp_u8` feature is enabled.
292    /// - Makes use of the `unsafe_str` feature if enabled.
293    #[cfg(feature = "_cmp_u8")] // const
294    #[cfg(feature = "_str_u8")]
295    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "string_u8")))]
296    pub const fn digits_str(self, width: u8) -> StringU8<5> {
297        let width = Compare(width).clamp(self.count_digits(), 5);
298
299        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
300        return unwrap![ok StringU8::<5>::from_bytes_nright(self.digits(), width)];
301        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
302        // SAFETY: the bytes are valid utf-8
303        unsafe {
304            StringU8::<5>::from_bytes_nright_unchecked(self.digits(), width)
305        }
306    }
307    #[allow(missing_docs)]
308    #[cfg(not(feature = "_cmp_u8"))] // !const
309    #[cfg(feature = "_str_u8")]
310    pub fn digits_str(self, width: u8) -> StringU8<5> {
311        let width = width.max(self.count_digits()).min(5);
312
313        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
314        return unwrap![ok StringU8::<5>::from_bytes_nright(self.digits(), width)];
315        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
316        // SAFETY: the bytes are valid utf-8
317        unsafe {
318            StringU8::<5>::from_bytes_nright_unchecked(self.digits(), width)
319        }
320    }
321
322    /// Converts a three-digit number to the corresponding `3` ASCII digits.
323    ///
324    /// # Panics
325    /// This function panics in debug if the given number is > 999.
326    #[must_use]
327    pub const fn digits_3(self) -> [u8; 3] {
328        debug_assert![self.0 <= 999];
329        [self.calc_digit(100), self.calc_digit(10), self.calc_digit(1)]
330    }
331
332    /// Converts a four-digit number to the corresponding `4` ASCII digits.
333    ///
334    /// # Panics
335    /// This function panics in debug if the given number is > 9999.
336    #[must_use]
337    pub const fn digits_4(self) -> [u8; 4] {
338        debug_assert![self.0 <= 9999];
339        [self.calc_digit(1000), self.calc_digit(100), self.calc_digit(10), self.calc_digit(1)]
340    }
341}
342
343impl Ascii<u32> {
344    /// The maximum number of decimal digits a `u32` can represent.
345    pub const MAX_DIGITS: usize = 10;
346
347    /// Returns the ASCII byte of a specific digit in a `u32` number.
348    ///
349    /// # Arguments
350    /// * `divisor`: A power of 10 used to determine which digit to extract.
351    ///
352    /// # Examples
353    /// ```
354    /// # use devela::text::Ascii;
355    /// assert_eq!(Ascii(12345_u32).calc_digit(10), b'4');
356    /// assert_eq!(Ascii(12345_u32).calc_digit(1000), b'2');
357    /// ```
358    #[must_use]
359    pub const fn calc_digit(self, divisor: u32) -> u8 {
360        (self.0 / divisor % 10) as u8 + b'0'
361    }
362
363    /// Counts the number of decimal digits.
364    ///
365    /// For more complex needs check the [`Int`][crate::num::Int] *base* methods.
366    /// # Examples
367    /// ```
368    /// # use devela::text::Ascii;
369    /// assert_eq![1, Ascii(0_u32).count_digits()];
370    /// assert_eq![4, Ascii(9876_u32).count_digits()];
371    /// ```
372    #[must_use]
373    pub const fn count_digits(self) -> u8 {
374        iif![self.0 == 0; 1; self.0.ilog10() as u8 + 1]
375    }
376
377    /// Converts a `u32` into a byte array of `10` ASCII digits with leading zeros.
378    ///
379    /// You can trim the leading zeros with
380    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
381    #[must_use]
382    #[allow(clippy::unreadable_literal)]
383    pub const fn digits(self) -> [u8; 10] {
384        [
385            //              0987654321
386            //              4294967295    ← u32::MAX
387            self.calc_digit(1000000000), // 10 digits
388            self.calc_digit(100000000),
389            self.calc_digit(10000000),
390            self.calc_digit(1000000),
391            self.calc_digit(100000),
392            self.calc_digit(10000), // 5 digits
393            self.calc_digit(1000),
394            self.calc_digit(100),
395            self.calc_digit(10),
396            self.calc_digit(1),
397        ]
398    }
399
400    /// Returns a static string with zero-padded digits with minimum `width`.
401    ///
402    /// The given `width` will be clamped betweeen the actual number of digits
403    /// and the maximum number of digits.
404    ///
405    /// # Features
406    /// - Will only be *const* if the `_cmp_u8` feature is enabled.
407    /// - Makes use of the `unsafe_str` feature if enabled.
408    #[cfg(feature = "_cmp_u8")] // const
409    #[cfg(feature = "_str_u8")]
410    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "string_u8")))]
411    pub const fn digits_str(self, width: u8) -> StringU8<10> {
412        let width = Compare(width).clamp(self.count_digits(), 10);
413
414        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
415        return unwrap![ok StringU8::<10>::from_bytes_nright(self.digits(), width)];
416        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
417        // SAFETY: the bytes are valid utf-8
418        unsafe {
419            StringU8::<10>::from_bytes_nright_unchecked(self.digits(), width)
420        }
421    }
422    #[allow(missing_docs)]
423    #[cfg(not(feature = "_cmp_u8"))] // !const
424    #[cfg(feature = "_str_u8")]
425    pub fn digits_str(self, width: u8) -> StringU8<10> {
426        let width = width.max(self.count_digits()).min(10);
427
428        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
429        return unwrap![ok StringU8::<10>::from_bytes_nright(self.digits(), width)];
430        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
431        // SAFETY: the bytes are valid utf-8
432        unsafe {
433            StringU8::<10>::from_bytes_nright_unchecked(self.digits(), width)
434        }
435    }
436}
437
438impl Ascii<u64> {
439    /// The maximum number of decimal digits a `u64` can represent.
440    pub const MAX_DIGITS: usize = 20;
441
442    /// Returns the ASCII byte of a specific digit in a `u64` number.
443    ///
444    /// # Arguments
445    /// * `divisor`: A power of 10 used to determine which digit to extract.
446    ///
447    /// # Examples
448    /// ```
449    /// # use devela::text::Ascii;
450    /// assert_eq!(Ascii(12345_u64).calc_digit(10), b'4');
451    /// assert_eq!(Ascii(12345_u64).calc_digit(1000), b'2');
452    /// ```
453    #[must_use]
454    pub const fn calc_digit(self, divisor: u64) -> u8 {
455        (self.0 / divisor % 10) as u8 + b'0'
456    }
457
458    /// Counts the number of decimal digits.
459    ///
460    /// For more complex needs check the [`Int`][crate::num::Int] *base* methods.
461    /// # Examples
462    /// ```
463    /// # use devela::text::Ascii;
464    /// assert_eq![1, Ascii(0_u64).count_digits()];
465    /// assert_eq![4, Ascii(9876_u64).count_digits()];
466    /// ```
467    #[must_use]
468    pub const fn count_digits(self) -> u8 {
469        iif![self.0 == 0; 1; self.0.ilog10() as u8 + 1]
470    }
471
472    /// Converts a `u64` into a byte array of `20` ascii digits with leading zeros.
473    ///
474    /// You can trim the leading zeros with
475    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
476    #[must_use]
477    #[allow(clippy::unreadable_literal)]
478    pub const fn digits(self) -> [u8; 20] {
479        [
480            //              0987654321_987654321
481            //              18446744073709551615    ← u64::MAX
482            self.calc_digit(10000000000000000000), // 20 digits
483            self.calc_digit(1000000000000000000),
484            self.calc_digit(100000000000000000),
485            self.calc_digit(10000000000000000),
486            self.calc_digit(1000000000000000),
487            self.calc_digit(100000000000000),
488            self.calc_digit(10000000000000),
489            self.calc_digit(1000000000000),
490            self.calc_digit(100000000000),
491            self.calc_digit(10000000000),
492            self.calc_digit(1000000000), // 10 digits
493            self.calc_digit(100000000),
494            self.calc_digit(10000000),
495            self.calc_digit(1000000),
496            self.calc_digit(100000),
497            self.calc_digit(10000),
498            self.calc_digit(1000),
499            self.calc_digit(100),
500            self.calc_digit(10),
501            self.calc_digit(1),
502        ]
503    }
504
505    /// Returns a static string with zero-padded digits with minimum `width`.
506    ///
507    /// The given `width` will be clamped betweeen the actual number of digits
508    /// and the maximum number of digits.
509    ///
510    /// # Features
511    /// - Will only be *const* if the `_cmp_u8` feature is enabled.
512    /// - Makes use of the `unsafe_str` feature if enabled.
513    #[cfg(feature = "_cmp_u8")] // const
514    #[cfg(feature = "_str_u8")]
515    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "string_u8")))]
516    pub const fn digits_str(self, width: u8) -> StringU8<20> {
517        let width = Compare(width).clamp(self.count_digits(), 20);
518
519        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
520        return unwrap![ok StringU8::<20>::from_bytes_nright(self.digits(), width)];
521        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
522        // SAFETY: the bytes are valid utf-8
523        unsafe {
524            StringU8::<20>::from_bytes_nright_unchecked(self.digits(), width)
525        }
526    }
527    #[allow(missing_docs)]
528    #[cfg(not(feature = "_cmp_u8"))] // !const
529    #[cfg(feature = "_str_u8")]
530    pub fn digits_str(self, width: u8) -> StringU8<20> {
531        let width = width.max(self.count_digits()).min(20);
532
533        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
534        return unwrap![ok StringU8::<20>::from_bytes_nright(self.digits(), width)];
535        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
536        // SAFETY: the bytes are valid utf-8
537        unsafe {
538            StringU8::<20>::from_bytes_nright_unchecked(self.digits(), width)
539        }
540    }
541}
542
543impl Ascii<u128> {
544    /// The maximum number of decimal digits a `u128` can represent.
545    pub const MAX_DIGITS: usize = 30;
546
547    /// Returns the ASCII byte of a specific digit in a `u128` number.
548    ///
549    /// # Arguments
550    /// * `divisor`: A power of 10 used to determine which digit to extract.
551    ///
552    /// # Examples
553    /// ```
554    /// # use devela::text::Ascii;
555    /// assert_eq!(Ascii(12345_u128).calc_digit(10), b'4');
556    /// assert_eq!(Ascii(12345_u128).calc_digit(1000), b'2');
557    /// ```
558    #[must_use]
559    pub const fn calc_digit(self, divisor: u128) -> u8 {
560        (self.0 / divisor % 10) as u8 + b'0'
561    }
562
563    /// Counts the number of decimal digits.
564    ///
565    /// For more complex needs check the [`Int`][crate::num::Int] *base* methods.
566    /// # Examples
567    /// ```
568    /// # use devela::text::Ascii;
569    /// assert_eq![1, Ascii(0_u128).count_digits()];
570    /// assert_eq![19, Ascii(9876543210987654321_u128).count_digits()];
571    /// ```
572    #[must_use]
573    pub const fn count_digits(self) -> u8 {
574        iif![self.0 == 0; 1; self.0.ilog10() as u8 + 1]
575    }
576
577    /// Converts a `u128` into a byte array of `39` ascii digits with leading zeros.
578    ///
579    /// You can trim the leading zeros with
580    /// [`trim_leading_bytes`][crate::Slice::trim_leading_bytes].
581    #[must_use]
582    #[allow(clippy::unreadable_literal)]
583    pub const fn digits(self) -> [u8; 39] {
584        [
585            //              987654321_987654321_987654321_987654321
586            //              340282366920938463463374607431768211455    ← u128::MAX
587            self.calc_digit(100000000000000000000000000000000000000), // 39 digits
588            self.calc_digit(10000000000000000000000000000000000000),
589            self.calc_digit(1000000000000000000000000000000000000),
590            self.calc_digit(100000000000000000000000000000000000),
591            self.calc_digit(10000000000000000000000000000000000),
592            self.calc_digit(1000000000000000000000000000000000),
593            self.calc_digit(100000000000000000000000000000000),
594            self.calc_digit(10000000000000000000000000000000),
595            self.calc_digit(1000000000000000000000000000000),
596            self.calc_digit(100000000000000000000000000000), // 30 digits
597            self.calc_digit(10000000000000000000000000000),
598            self.calc_digit(1000000000000000000000000000),
599            self.calc_digit(100000000000000000000000000),
600            self.calc_digit(10000000000000000000000000),
601            self.calc_digit(1000000000000000000000000),
602            self.calc_digit(100000000000000000000000),
603            self.calc_digit(10000000000000000000000),
604            self.calc_digit(1000000000000000000000),
605            self.calc_digit(100000000000000000000),
606            self.calc_digit(10000000000000000000), // 20 digits
607            self.calc_digit(1000000000000000000),
608            self.calc_digit(100000000000000000),
609            self.calc_digit(10000000000000000),
610            self.calc_digit(1000000000000000),
611            self.calc_digit(100000000000000),
612            self.calc_digit(10000000000000),
613            self.calc_digit(1000000000000),
614            self.calc_digit(100000000000),
615            self.calc_digit(10000000000),
616            self.calc_digit(1000000000), // 10 digits
617            self.calc_digit(100000000),
618            self.calc_digit(10000000),
619            self.calc_digit(1000000),
620            self.calc_digit(100000),
621            self.calc_digit(10000),
622            self.calc_digit(1000),
623            self.calc_digit(100),
624            self.calc_digit(10),
625            self.calc_digit(1),
626        ]
627    }
628
629    /// Returns a static string with zero-padded digits with minimum `width`.
630    ///
631    /// The given `width` will be clamped betweeen the actual number of digits
632    /// and the maximum number of digits.
633    ///
634    /// # Features
635    /// - Will only be *const* if the `_cmp_u8` feature is enabled.
636    /// - Makes use of the `unsafe_str` feature if enabled.
637    #[cfg(feature = "_cmp_u8")] // const
638    #[cfg(feature = "_str_u8")]
639    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "string_u8")))]
640    pub const fn digits_str(self, width: u8) -> StringU8<39> {
641        let width = Compare(width).clamp(self.count_digits(), 39);
642
643        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
644        return unwrap![ok StringU8::<39>::from_bytes_nright(self.digits(), width)];
645        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
646        // SAFETY: the bytes are valid utf-8
647        unsafe {
648            StringU8::<39>::from_bytes_nright_unchecked(self.digits(), width)
649        }
650    }
651    #[cfg(not(feature = "_cmp_u8"))] // !const
652    #[cfg(feature = "_str_u8")]
653    #[allow(missing_docs)]
654    pub fn digits_str(self, width: u8) -> StringU8<39> {
655        let width = width.max(self.count_digits()).min(39);
656
657        #[cfg(any(feature = "safe_text", not(feature = "unsafe_str")))]
658        return unwrap![ok StringU8::<39>::from_bytes_nright(self.digits(), width)];
659        #[cfg(all(not(feature = "safe_text"), feature = "unsafe_str"))]
660        // SAFETY: the bytes are valid utf-8
661        unsafe {
662            StringU8::<39>::from_bytes_nright_unchecked(self.digits(), width)
663        }
664    }
665}