const_str/__ctfe/
to_str.rs1#![allow(unsafe_code)]
2
3use super::str::StrBuf;
4use crate::utf8::CharEncodeUtf8;
5
6pub struct ToStr<T>(pub T);
7
8impl ToStr<&str> {
9 pub const fn output_len(&self) -> usize {
10 self.0.len()
11 }
12
13 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
14 StrBuf::from_str(self.0)
15 }
16}
17
18impl ToStr<bool> {
19 const fn bool_to_str(b: bool) -> &'static str {
20 if b {
21 "true"
22 } else {
23 "false"
24 }
25 }
26
27 pub const fn output_len(&self) -> usize {
28 Self::bool_to_str(self.0).len()
29 }
30
31 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
32 let bytes: &[u8] = Self::bool_to_str(self.0).as_bytes();
33 let buf = crate::bytes::merge([0; N], bytes);
34 unsafe { StrBuf::new_unchecked(buf) }
35 }
36}
37
38impl ToStr<char> {
39 pub const fn output_len(&self) -> usize {
40 self.0.len_utf8()
41 }
42
43 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
44 let ch = CharEncodeUtf8::new(self.0);
45 let buf = crate::bytes::merge([0; N], ch.as_bytes());
46 unsafe { StrBuf::new_unchecked(buf) }
47 }
48}
49
50macro_rules! impl_integer_to_str {
51 ($unsigned: ty, $signed: ty) => {
52 impl ToStr<$unsigned> {
53 pub const fn output_len(&self) -> usize {
54 let mut x = self.0;
55 let mut ans = 1;
56 while x > 9 {
57 ans += 1;
58 x /= 10;
59 }
60 ans
61 }
62
63 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
64 let mut buf = [0; N];
65 let mut pos = 0;
66 let mut x = self.0;
67 loop {
68 buf[pos] = b'0' + (x % 10) as u8;
69 pos += 1;
70 x /= 10;
71 if x == 0 {
72 break;
73 }
74 }
75 assert!(pos == N);
76 let buf = crate::bytes::reversed(buf);
77 unsafe { StrBuf::new_unchecked(buf) }
78 }
79 }
80
81 impl ToStr<$signed> {
82 pub const fn output_len(&self) -> usize {
83 let x = self.0;
84 let abs_len = ToStr(x.unsigned_abs()).output_len();
85 abs_len + (x < 0) as usize
86 }
87
88 pub const fn const_eval<const N: usize>(&self) -> StrBuf<N> {
89 let mut buf = [0; N];
90 let mut pos = 0;
91
92 let mut x = self.0.unsigned_abs();
93
94 loop {
95 buf[pos] = b'0' + (x % 10) as u8;
96 pos += 1;
97 x /= 10;
98 if x == 0 {
99 break;
100 }
101 }
102
103 if self.0 < 0 {
104 buf[pos] = b'-';
105 pos += 1;
106 }
107
108 assert!(pos == N);
109 let buf = crate::bytes::reversed(buf);
110 unsafe { StrBuf::new_unchecked(buf) }
111 }
112 }
113 };
114}
115
116impl_integer_to_str!(u8, i8);
117impl_integer_to_str!(u16, i16);
118impl_integer_to_str!(u32, i32);
119impl_integer_to_str!(u64, i64);
120impl_integer_to_str!(u128, i128);
121impl_integer_to_str!(usize, isize);
122
123#[macro_export]
155macro_rules! to_str {
156 ($x: expr) => {{
157 const OUTPUT_LEN: usize = $crate::__ctfe::ToStr($x).output_len();
158 const OUTPUT_BUF: $crate::__ctfe::StrBuf<OUTPUT_LEN> =
159 $crate::__ctfe::ToStr($x).const_eval();
160 OUTPUT_BUF.as_str()
161 }};
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_to_str() {
170 macro_rules! test_to_str {
171 ($ty: ty, $x: expr) => {{
172 const X: $ty = $x;
173 const OUTPUT_LEN: usize = ToStr(X).output_len();
174 const OUTPUT_BUF: StrBuf<OUTPUT_LEN> = ToStr(X).const_eval();
175
176 let output = OUTPUT_BUF.as_str();
177 let ans = X.to_string();
178 assert_eq!(OUTPUT_LEN, ans.len());
179 assert_eq!(output, ans);
180 }};
181 }
182
183 test_to_str!(&str, "lovelive superstar");
184
185 test_to_str!(bool, true);
186 test_to_str!(bool, false);
187
188 test_to_str!(char, '鲤');
189 test_to_str!(char, '鱼');
190
191 test_to_str!(u8, 0);
192 test_to_str!(u16, 0);
193 test_to_str!(u32, 0);
194 test_to_str!(u64, 0);
195 test_to_str!(u128, 0);
196
197 test_to_str!(u8, 10);
198 test_to_str!(u8, 128);
199 test_to_str!(u8, u8::MAX);
200
201 test_to_str!(u64, 1);
202 test_to_str!(u64, 10);
203 test_to_str!(u64, 42);
204 test_to_str!(u64, u64::MAX);
205
206 test_to_str!(u128, u128::MAX);
207
208 test_to_str!(i8, 0);
209 test_to_str!(i16, 0);
210 test_to_str!(i32, 0);
211 test_to_str!(i64, 0);
212 test_to_str!(i128, 0);
213
214 test_to_str!(i8, -10);
215 test_to_str!(i8, -42);
216 test_to_str!(i8, i8::MAX);
217 test_to_str!(i8, i8::MIN);
218
219 test_to_str!(i64, 1);
220 test_to_str!(i64, 10);
221 test_to_str!(i64, -42);
222 test_to_str!(i64, i64::MAX);
223 test_to_str!(i64, i64::MIN);
224
225 test_to_str!(i128, i128::MAX);
226 test_to_str!(i128, i128::MIN);
227 }
228}