1#![allow(unsafe_code)]
2
3use super::StrBuf;
4use super::ToStr;
5
6use crate::slice::advance;
7use crate::utf8::CharEscapeDebug;
8use crate::utf8::CharEscapeDebugArgs;
9
10#[derive(Clone, Copy)]
11pub struct FmtSpec {
12 pub alternate: bool,
13}
14
15pub struct Display<T>(pub T, pub FmtSpec);
16
17macro_rules! delegate_display {
18 ($($ty: ty,)+) => {
19 $(
20 impl Display<$ty> {
21 pub const fn output_len(&self) -> usize {
22 ToStr(self.0).output_len()
23 }
24
25 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
26 ToStr(self.0).const_eval()
27 }
28 }
29 )+
30 };
31}
32
33delegate_display!(&str, char, bool, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize,);
34
35#[doc(hidden)]
36#[macro_export]
37macro_rules! __fmt_display {
38 ($x: expr, $spec: expr) => {{
39 const OUTPUT_LEN: usize = $crate::__ctfe::Display($x, $spec).output_len();
40 const OUTPUT_BUF: $crate::__ctfe::StrBuf<OUTPUT_LEN> =
41 $crate::__ctfe::Display($x, $spec).const_eval();
42 OUTPUT_BUF.as_str()
43 }};
44}
45
46pub struct Debug<T>(pub T, pub FmtSpec);
47
48macro_rules! delegate_debug {
49 ($($ty: ty,)+) => {
50 $(
51 impl Debug<$ty> {
52 pub const fn output_len(&self) -> usize {
53 ToStr(self.0).output_len()
54 }
55
56 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
57 ToStr(self.0).const_eval()
58 }
59 }
60 )+
61 };
62}
63
64delegate_debug!(bool, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize,);
65
66impl Debug<char> {
67 pub const fn output_len(&self) -> usize {
68 let escape = CharEscapeDebug::new(
69 self.0,
70 CharEscapeDebugArgs {
71 escape_single_quote: true,
72 escape_double_quote: false,
73 },
74 );
75
76 escape.as_bytes().len() + 2
77 }
78
79 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
80 let mut buf = [0; N];
81 let mut pos = 0;
82
83 macro_rules! push {
84 ($x: expr) => {{
85 buf[pos] = $x;
86 pos += 1;
87 }};
88 }
89
90 push!(b'\'');
91 {
92 let e = CharEscapeDebug::new(
93 self.0,
94 CharEscapeDebugArgs {
95 escape_single_quote: true,
96 escape_double_quote: false,
97 },
98 );
99 let bytes = e.as_bytes();
100 let mut i = 0;
101 while i < bytes.len() {
102 push!(bytes[i]);
103 i += 1;
104 }
105 }
106 push!(b'\'');
107
108 assert!(pos == N);
109
110 unsafe { StrBuf::new_unchecked(buf) }
111 }
112}
113
114impl Debug<&str> {
115 pub const fn output_len(&self) -> usize {
116 let mut s = self.0.as_bytes();
117 let mut ans = 2;
118 while let Some((ch, count)) = crate::utf8::next_char(s) {
119 s = advance(s, count);
120 let e = CharEscapeDebug::new(
121 ch,
122 CharEscapeDebugArgs {
123 escape_single_quote: false,
124 escape_double_quote: true,
125 },
126 );
127 ans += e.as_bytes().len()
128 }
129 ans
130 }
131
132 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
133 let mut buf = [0; N];
134 let mut pos = 0;
135
136 macro_rules! push {
137 ($x: expr) => {{
138 buf[pos] = $x;
139 pos += 1;
140 }};
141 }
142
143 push!(b'"');
144
145 let mut s = self.0.as_bytes();
146 while let Some((ch, count)) = crate::utf8::next_char(s) {
147 s = advance(s, count);
148 let e = CharEscapeDebug::new(
149 ch,
150 CharEscapeDebugArgs {
151 escape_single_quote: false,
152 escape_double_quote: true,
153 },
154 );
155 let bytes = e.as_bytes();
156 let mut i = 0;
157 while i < bytes.len() {
158 push!(bytes[i]);
159 i += 1;
160 }
161 }
162
163 push!(b'"');
164
165 assert!(pos == N);
166
167 unsafe { StrBuf::new_unchecked(buf) }
168 }
169}
170
171#[doc(hidden)]
172#[macro_export]
173macro_rules! __fmt_debug {
174 ($x: expr, $spec: expr) => {{
175 const OUTPUT_LEN: usize = $crate::__ctfe::Debug($x, $spec).output_len();
176 const OUTPUT_BUF: $crate::__ctfe::StrBuf<OUTPUT_LEN> =
177 $crate::__ctfe::Debug($x, $spec).const_eval();
178 OUTPUT_BUF.as_str()
179 }};
180}
181
182struct Hex<T>(T, FmtSpec, bool);
183
184pub struct LowerHex<T>(pub T, pub FmtSpec);
185pub struct UpperHex<T>(pub T, pub FmtSpec);
186
187macro_rules! impl_integer_hex {
188 ($unsigned: ty, $signed: ty) => {
189 impl Hex<$unsigned> {
190 const fn output_len(&self) -> usize {
191 let mut x = self.0;
192 let mut ans = 0;
193 loop {
194 ans += 1;
195 x /= 16;
196 if x == 0 {
197 break;
198 }
199 }
200 if self.1.alternate {
201 ans += 2;
202 }
203 ans
204 }
205
206 const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
207 let mut buf = [0; N];
208 let mut pos = 0;
209 let mut x = self.0;
210 loop {
211 let d = crate::ascii::num_to_hex_digit((x % 16) as u8);
212 buf[pos] = if self.2 { d.to_ascii_uppercase() } else { d };
213 pos += 1;
214 x /= 16;
215 if x == 0 {
216 break;
217 }
218 }
219 if self.1.alternate {
220 buf[pos] = b'x';
221 pos += 1;
222 buf[pos] = b'0';
223 pos += 1;
224 }
225 assert!(pos == N);
226 let buf = crate::bytes::reversed(buf);
227 unsafe { StrBuf::new_unchecked(buf) }
228 }
229 }
230
231 impl LowerHex<$unsigned> {
232 pub const fn output_len(&self) -> usize {
233 let h = Hex(self.0, self.1, false);
234 h.output_len()
235 }
236
237 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
238 let h = Hex(self.0, self.1, false);
239 h.const_eval()
240 }
241 }
242
243 impl UpperHex<$unsigned> {
244 pub const fn output_len(&self) -> usize {
245 let h = Hex(self.0, self.1, true);
246 h.output_len()
247 }
248
249 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
250 let h = Hex(self.0, self.1, true);
251 h.const_eval()
252 }
253 }
254
255 impl LowerHex<$signed> {
256 pub const fn output_len(&self) -> usize {
257 let h = Hex(self.0 as $unsigned, self.1, false);
258 h.output_len()
259 }
260
261 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
262 let h = Hex(self.0 as $unsigned, self.1, false);
263 h.const_eval()
264 }
265 }
266
267 impl UpperHex<$signed> {
268 pub const fn output_len(&self) -> usize {
269 let h = Hex(self.0 as $unsigned, self.1, true);
270 h.output_len()
271 }
272
273 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
274 let h = Hex(self.0 as $unsigned, self.1, true);
275 h.const_eval()
276 }
277 }
278 };
279}
280
281impl_integer_hex!(u8, i8);
282impl_integer_hex!(u16, i16);
283impl_integer_hex!(u32, i32);
284impl_integer_hex!(u64, i64);
285impl_integer_hex!(u128, i128);
286impl_integer_hex!(usize, isize);
287
288#[doc(hidden)]
289#[macro_export]
290macro_rules! __fmt_lowerhex {
291 ($x: expr, $spec: expr) => {{
292 const OUTPUT_LEN: usize = $crate::__ctfe::LowerHex($x, $spec).output_len();
293 const OUTPUT_BUF: $crate::__ctfe::StrBuf<OUTPUT_LEN> =
294 $crate::__ctfe::LowerHex($x, $spec).const_eval();
295 OUTPUT_BUF.as_str()
296 }};
297}
298
299#[doc(hidden)]
300#[macro_export]
301macro_rules! __fmt_upperhex {
302 ($x: expr, $spec: expr) => {{
303 const OUTPUT_LEN: usize = $crate::__ctfe::UpperHex($x, $spec).output_len();
304 const OUTPUT_BUF: $crate::__ctfe::StrBuf<OUTPUT_LEN> =
305 $crate::__ctfe::UpperHex($x, $spec).const_eval();
306 OUTPUT_BUF.as_str()
307 }};
308}
309
310pub struct Binary<T>(pub T, pub FmtSpec);
311
312macro_rules! impl_integer_binary {
313 ($unsigned: ty, $signed: ty) => {
314 impl Binary<$unsigned> {
315 pub const fn output_len(&self) -> usize {
316 let mut x = self.0;
317 let mut ans = 0;
318 loop {
319 ans += 1;
320 x /= 2;
321 if x == 0 {
322 break;
323 }
324 }
325 if self.1.alternate {
326 ans += 2;
327 }
328 ans
329 }
330
331 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
332 let mut buf = [0; N];
333 let mut pos = 0;
334 let mut x = self.0;
335 loop {
336 buf[pos] = b'0' + (x % 2) as u8;
337 pos += 1;
338 x /= 2;
339 if x == 0 {
340 break;
341 }
342 }
343 if self.1.alternate {
344 buf[pos] = b'b';
345 pos += 1;
346 buf[pos] = b'0';
347 pos += 1;
348 }
349 assert!(pos == N);
350 let buf = crate::bytes::reversed(buf);
351 unsafe { StrBuf::new_unchecked(buf) }
352 }
353 }
354
355 impl Binary<$signed> {
356 pub const fn output_len(&self) -> usize {
357 let b = Binary(self.0 as $unsigned, self.1);
358 b.output_len()
359 }
360
361 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
362 let b = Binary(self.0 as $unsigned, self.1);
363 b.const_eval()
364 }
365 }
366 };
367}
368
369impl_integer_binary!(u8, i8);
370impl_integer_binary!(u16, i16);
371impl_integer_binary!(u32, i32);
372impl_integer_binary!(u64, i64);
373impl_integer_binary!(u128, i128);
374impl_integer_binary!(usize, isize);
375
376#[doc(hidden)]
377#[macro_export]
378macro_rules! __fmt_binary {
379 ($x: expr, $spec: expr) => {{
380 const OUTPUT_LEN: usize = $crate::__ctfe::Binary($x, $spec).output_len();
381 const OUTPUT_BUF: $crate::__ctfe::StrBuf<OUTPUT_LEN> =
382 $crate::__ctfe::Binary($x, $spec).const_eval();
383 OUTPUT_BUF.as_str()
384 }};
385}