const_panic/
int_formatting.rs

1use crate::{
2    fmt::{FmtArg, NumberFmt},
3    utils::{Sign, TailShortString},
4};
5
6pub(crate) const fn fmt_decimal<const N: usize>(sign: Sign, mut n: u128) -> TailShortString<N> {
7    let mut start = N;
8    let mut buffer = [0u8; N];
9
10    loop {
11        start -= 1;
12        let digit = (n % 10) as u8;
13        buffer[start] = b'0' + digit;
14        n /= 10;
15        if n == 0 {
16            break;
17        }
18    }
19
20    if let Sign::Negative = sign {
21        start -= 1;
22        buffer[start] = b'-';
23    }
24
25    // safety: buffer is only ever written ascii, so its automatically valid utf8.
26    unsafe { TailShortString::new(start as u8, buffer) }
27}
28
29pub(crate) const fn fmt_binary<const N: usize>(
30    mut n: u128,
31    is_alternate: bool,
32) -> TailShortString<N> {
33    let mut start = N;
34    let mut buffer = [0u8; N];
35
36    loop {
37        start -= 1;
38        let digit = (n & 1) as u8;
39        buffer[start] = b'0' + digit;
40        n >>= 1;
41        if n == 0 {
42            break;
43        }
44    }
45
46    if is_alternate {
47        start -= 1;
48        buffer[start] = b'b';
49        start -= 1;
50        buffer[start] = b'0';
51    }
52
53    // safety: buffer is only ever written ascii, so its automatically valid utf8.
54    unsafe { TailShortString::new(start as u8, buffer) }
55}
56
57pub(crate) const fn fmt_hexadecimal<const N: usize>(
58    mut n: u128,
59    is_alternate: bool,
60) -> TailShortString<N> {
61    let mut start = N;
62    let mut buffer = [0u8; N];
63
64    loop {
65        start -= 1;
66        let digit = (n & 0xF) as u8;
67        buffer[start] = match digit {
68            0..=9 => b'0' + digit,
69            _ => b'A' - 10 + digit,
70        };
71        n >>= 4;
72        if n == 0 {
73            break;
74        }
75    }
76
77    if is_alternate {
78        start -= 1;
79        buffer[start] = b'x';
80        start -= 1;
81        buffer[start] = b'0';
82    }
83
84    // safety: buffer is only ever written ascii, so its automatically valid utf8.
85    unsafe { TailShortString::new(start as u8, buffer) }
86}
87
88pub(crate) const fn compute_len(sign: Sign, int: u128, bits: u8, fmt: FmtArg) -> u8 {
89    match fmt.number_fmt {
90        NumberFmt::Decimal => compute_decimal_len(sign, int),
91        NumberFmt::Hexadecimal => {
92            let with_0x = (fmt.is_alternate as u8) * 2;
93            let i = match sign {
94                Sign::Negative => bits,
95                Sign::Positive => (128 - int.leading_zeros()) as u8,
96            };
97            let tmp = if i == 0 {
98                1
99            } else {
100                i / 4 + (i % 4 != 0) as u8
101            };
102            tmp + with_0x
103        }
104        NumberFmt::Binary => {
105            let with_0b = (fmt.is_alternate as u8) * 2;
106            let i = match sign {
107                Sign::Negative => bits,
108                Sign::Positive => (128 - int.leading_zeros()) as u8,
109            };
110            (if i == 0 { 1 } else { i }) + with_0b
111        }
112    }
113}
114
115const fn compute_decimal_len(sign: Sign, mut n: u128) -> u8 {
116    let mut len = matches!(sign, Sign::Negative) as u8 + 1;
117    if n >= 1_0000_0000_0000_0000 {
118        n /= 1_0000_0000_0000_0000;
119        len += 16;
120    }
121    if n >= 1_0000_0000_0000 {
122        n /= 1_0000_0000_0000;
123        len += 12;
124    }
125    if n >= 1_0000_0000 {
126        n /= 100_000_000;
127        len += 8;
128    }
129    if n >= 1_0000 {
130        n /= 1_0000;
131        len += 4;
132    }
133    if n >= 100 {
134        n /= 100;
135        len += 2;
136    }
137    if n >= 10 {
138        len += 1;
139    }
140    len
141}