konst_kernel/string/
string_for_konst.rs1#![allow(clippy::len_without_is_empty)]
2
3use crate::chr::{encode_utf8, Utf8Encoded};
4
5#[doc(hidden)]
6pub struct __NormalizeConcatArg<T: 'static>(pub &'static [T]);
7
8impl __NormalizeConcatArg<char> {
9 pub const fn conv(self) -> __StrConcatArg {
10 __StrConcatArg::Char(self.0)
11 }
12}
13
14impl __NormalizeConcatArg<&'static str> {
15 pub const fn conv(self) -> __StrConcatArg {
16 __StrConcatArg::Str(self.0)
17 }
18}
19
20#[doc(hidden)]
21#[derive(Copy, Clone)]
22pub enum __StrConcatArg {
23 Char(&'static [char]),
24 Str(&'static [&'static str]),
25}
26
27#[doc(hidden)]
28pub struct __MakeSepArg<T>(pub T);
29
30#[doc(hidden)]
31#[derive(Copy, Clone)]
32pub enum __SepArg {
33 Char(char),
34 Str(&'static str),
35}
36
37impl __SepArg {
38 const fn len(self) -> usize {
39 match self {
40 Self::Char(x) => x.len_utf8(),
41 Self::Str(x) => x.len(),
42 }
43 }
44}
45
46#[doc(hidden)]
47pub struct __ElemDispatch<T>(pub T);
48
49macro_rules! __ref_unref_impls {
50 ($($ref_token:tt $deref_token:tt)?) => {
51 impl __MakeSepArg<$($ref_token)? char> {
52 pub const fn conv(self) -> __SepArg {
53 __SepArg::Char($($deref_token)? self.0)
54 }
55 }
56
57 impl __MakeSepArg<$($ref_token)? &'static str> {
58 pub const fn conv(self) -> __SepArg {
59 __SepArg::Str(self.0)
60 }
61 }
62
63 impl __ElemDispatch<$($ref_token)? char> {
64 pub const fn as_bytesable(self) -> Utf8Encoded {
65 encode_utf8($($deref_token)? self.0)
66 }
67 pub const fn len(self) -> usize {
68 self.0.len_utf8()
69 }
70 }
71
72 impl __ElemDispatch<$($ref_token)? &'static str> {
73 pub const fn as_bytesable(self) -> &'static str {
74 self.0
75 }
76 pub const fn len(self) -> usize {
77 self.0.len()
78 }
79 }
80 };
81}
82
83__ref_unref_impls! {}
84__ref_unref_impls! {& *}
85
86#[doc(hidden)]
87#[macro_export]
88macro_rules! __with_str_concat_slices {
89 ($arg:expr, |$slices:ident| $with_slices:expr) => {
90 match $arg {
91 $crate::string::__StrConcatArg::Char($slices) => $with_slices,
92 $crate::string::__StrConcatArg::Str($slices) => $with_slices,
93 }
94 };
95}
96
97#[macro_export]
100macro_rules! string_concat {
101 ($(&)? []) => {
102 ""
103 };
104 ($slice:expr $(,)*) => {{
105 const __ARGS_81608BFNA5: $crate::string::__StrConcatArg =
106 $crate::string::__NormalizeConcatArg($slice).conv();
107 {
108 const LEN: $crate::__::usize = $crate::string::concat_sum_lengths(__ARGS_81608BFNA5);
109
110 const CONC: &$crate::string::ArrayStr<LEN> =
111 &$crate::string::concat_strs(__ARGS_81608BFNA5);
112
113 const STR: &$crate::__::str = CONC.as_str();
114
115 STR
116 }
117 }};
118}
119
120pub const fn concat_sum_lengths(arg: __StrConcatArg) -> usize {
121 let mut sum = 0usize;
122
123 __with_str_concat_slices! {arg, |slices| {
124 crate::for_range! {i in 0..slices.len() =>
125 sum += __ElemDispatch(slices[i]).len();
126 }
127 }}
128
129 sum
130}
131
132pub const fn concat_strs<const N: usize>(arg: __StrConcatArg) -> ArrayStr<N> {
133 let mut out = [0u8; N];
134 let mut out_i = 0usize;
135
136 __with_str_concat_slices! {arg, |slices| {
137 crate::for_range! {si in 0..slices.len() =>
138 let byteser = __ElemDispatch(slices[si]).as_bytesable();
139 let slice = byteser.as_bytes();
140 crate::for_range! {i in 0..slice.len() =>
141 out[out_i] = slice[i];
142 out_i += 1;
143 }
144 }
145 }}
146
147 ArrayStr(out)
148}
149
150#[macro_export]
153macro_rules! string_join {
154 ($sep:expr, $(&)? []) => {
155 ""
156 };
157 ($sep:expr, $slice:expr $(,)*) => {{
158 const __ARGS_81608BFNA5: $crate::string::StrJoinArgs = $crate::string::StrJoinArgs {
159 sep: $crate::string::__MakeSepArg($sep).conv(),
160 slice: $slice,
161 };
162
163 {
164 const LEN: $crate::__::usize = $crate::string::join_sum_lengths(__ARGS_81608BFNA5);
165
166 const CONC: &$crate::string::ArrayStr<LEN> =
167 &$crate::string::join_strs(__ARGS_81608BFNA5);
168
169 const STR: &$crate::__::str = CONC.as_str();
170
171 STR
172 }
173 }};
174}
175
176#[derive(Copy, Clone)]
177pub struct StrJoinArgs {
178 pub sep: __SepArg,
179 pub slice: &'static [&'static str],
180}
181
182pub const fn join_sum_lengths(StrJoinArgs { sep, slice }: StrJoinArgs) -> usize {
183 if slice.is_empty() {
184 0
185 } else {
186 concat_sum_lengths(__StrConcatArg::Str(slice)) + sep.len() * (slice.len() - 1)
187 }
188}
189
190pub const fn join_strs<const N: usize>(
191 StrJoinArgs { sep, slice: slices }: StrJoinArgs,
192) -> ArrayStr<N> {
193 let mut out = [0u8; N];
194 let mut out_i = 0usize;
195
196 let utf8e: Utf8Encoded;
197 let sep = match sep {
198 __SepArg::Char(c) => {
199 utf8e = encode_utf8(c);
200 utf8e.as_str()
201 }
202 __SepArg::Str(s) => s,
203 };
204
205 macro_rules! write_str {
206 ($str:expr) => {{
207 let slice = $str.as_bytes();
208 crate::for_range! {i in 0..slice.len() =>
209 out[out_i] = slice[i];
210 out_i += 1;
211 }
212 }};
213 }
214
215 if let [first, rem_slices @ ..] = slices {
216 write_str! {first}
217
218 crate::for_range! {si in 0..rem_slices.len() =>
219 write_str!{sep}
220 write_str!{rem_slices[si]}
221 }
222 }
223
224 ArrayStr(out)
225}
226
227#[macro_export]
230macro_rules! str_from_iter {
231 ($($rem:tt)*) => {{
232 $crate::__collect_const_iter_with!{
233 $crate::__::u8,
234 {},
235 |array, written_length, item| {
236 let byteser = $crate::string::__ElemDispatch(item).as_bytesable();
237 let bytes = byteser.as_bytes();
238 let item_len = bytes.len();
239 let mut i = written_length;
240 let mut j = 0;
241 while j < item_len {
242 array[i] = $crate::__::MaybeUninit::new(bytes[j]);
243 i += 1;
244 j += 1;
245 }
246 },
247 elem_length = {
248 $crate::string::__ElemDispatch(item).len()
249 },
250 =>
251 $($rem)*
252 }
253
254 const __STR81608BFNA5: &$crate::__::str =
255 match core::str::from_utf8(&__ARR81608BFNA5) {
256 $crate::__::Ok(x) => x,
257 $crate::__::Err(_) => $crate::__::panic!("created string isn't UTF8"),
258 };
259
260 __STR81608BFNA5
261 }}
262}
263
264pub struct ArrayStr<const N: usize>([u8; N]);
267
268impl<const N: usize> ArrayStr<N> {
269 pub const fn as_str(&self) -> &str {
270 match core::str::from_utf8(&self.0) {
271 Ok(s) => s,
272 Err(_) => panic!("bug: konst made an invalid string"),
273 }
274 }
275}