const_str/__ctfe/
encode.rs1use crate::slice::advance;
2use crate::utf16::CharEncodeUtf16;
3
4pub struct Utf8Encoder {
5 pub nul_terminated: bool,
6}
7
8pub struct Utf16Encoder {
9 pub nul_terminated: bool,
10}
11
12pub struct Encode<'a, T>(pub &'a str, pub T);
13
14impl Encode<'_, Utf8Encoder> {
15 pub const fn output_len(&self) -> usize {
16 if self.1.nul_terminated {
17 self.0.len() + 1
18 } else {
19 self.0.len()
20 }
21 }
22
23 pub const fn const_eval<const N: usize>(&self) -> [u8; N] {
24 let bytes = self.0.as_bytes();
25 if self.1.nul_terminated {
26 let mut buf = [0; N];
27 let mut i = 0;
28 while i < bytes.len() {
29 let b = bytes[i];
30 assert!(b != 0);
31 buf[i] = b;
32 i += 1;
33 }
34 assert!(i + 1 == N);
35 buf
36 } else {
37 crate::bytes::clone(bytes)
38 }
39 }
40}
41
42impl Encode<'_, Utf16Encoder> {
43 pub const fn output_len(&self) -> usize {
44 crate::utf16::str_len_utf16(self.0) + (self.1.nul_terminated as usize)
45 }
46
47 pub const fn const_eval<const N: usize>(&self) -> [u16; N] {
48 let mut s = self.0.as_bytes();
49
50 let mut buf = [0; N];
51 let mut pos = 0;
52
53 while let Some((code, count)) = crate::utf8::next_char(s) {
54 s = advance(s, count);
55 let e = CharEncodeUtf16::new(code);
56
57 buf[pos] = e.first();
58 pos += 1;
59
60 if e.has_second() {
61 buf[pos] = e.second();
62 pos += 1;
63 }
64
65 if self.1.nul_terminated {
66 assert!(buf[pos - 1] != 0);
67 if e.has_second() {
68 assert!(buf[pos - 2] != 0);
69 }
70 }
71 }
72
73 if self.1.nul_terminated {
74 pos += 1;
75 }
76
77 assert!(pos == N);
78
79 buf
80 }
81}
82
83#[doc(hidden)]
84#[macro_export]
85macro_rules! __encoder {
86 (utf8) => {{
87 $crate::__ctfe::Utf8Encoder {
88 nul_terminated: false,
89 }
90 }};
91 (utf8_z) => {{
92 $crate::__ctfe::Utf8Encoder {
93 nul_terminated: true,
94 }
95 }};
96 (utf16) => {{
97 $crate::__ctfe::Utf16Encoder {
98 nul_terminated: false,
99 }
100 }};
101 (utf16_z) => {{
102 $crate::__ctfe::Utf16Encoder {
103 nul_terminated: true,
104 }
105 }};
106}
107
108#[doc(hidden)]
109#[macro_export]
110macro_rules! __encode {
111 ($e: tt, $s: expr) => {{
112 const OUTPUT_LEN: usize = $crate::__ctfe::Encode($s, $crate::__encoder!($e)).output_len();
113 &{ $crate::__ctfe::Encode($s, $crate::__encoder!($e)).const_eval::<OUTPUT_LEN>() }
114 }};
115}
116
117#[macro_export]
140macro_rules! encode {
141 (utf8, $s: expr) => {
142 $crate::__encode!(utf8, $s)
143 };
144 (utf16, $s: expr) => {
145 $crate::__encode!(utf16, $s)
146 };
147}
148
149#[macro_export]
171macro_rules! encode_z {
172 (utf8, $s: expr) => {
173 $crate::__encode!(utf8_z, $s)
174 };
175 (utf16, $s: expr) => {
176 $crate::__encode!(utf16_z, $s)
177 };
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_encode() {
186 {
187 const S: &str = "abc你好";
188 const B1: &[u8; 9] = encode!(utf8, S);
189 const B2: &[u8] = encode!(utf8, S);
190 const B3: &[u8; 10] = encode_z!(utf8, S);
191 let mut ans = S.as_bytes().to_owned();
192 assert_eq!(B1, ans.as_slice());
193 assert_eq!(B2, B1);
194 ans.push(0);
195 assert_eq!(B3, ans.as_slice());
196 }
197 {
198 const S: &str = "abc你好𤭢";
199 const B1: &[u16; 7] = encode!(utf16, S);
200 const B2: &[u16; 8] = encode_z!(utf16, S);
201 let mut ans = S.encode_utf16().collect::<Vec<_>>();
202 assert_eq!(B1, ans.as_slice());
203 ans.push(0);
204 assert_eq!(B2, ans.as_slice());
205 }
206 }
207
208 #[test]
209 fn test_encode_runtime() {
210 let encoder_utf8 = Encode(
212 "test",
213 Utf8Encoder {
214 nul_terminated: false,
215 },
216 );
217 assert_eq!(encoder_utf8.output_len(), 4);
218 let buf: [u8; 4] = encoder_utf8.const_eval();
219 assert_eq!(&buf, b"test");
220
221 let encoder_utf8_z = Encode(
222 "hello",
223 Utf8Encoder {
224 nul_terminated: true,
225 },
226 );
227 assert_eq!(encoder_utf8_z.output_len(), 6);
228 let buf2: [u8; 6] = encoder_utf8_z.const_eval();
229 assert_eq!(&buf2, b"hello\0");
230
231 let encoder_utf16 = Encode(
233 "abc",
234 Utf16Encoder {
235 nul_terminated: false,
236 },
237 );
238 assert_eq!(encoder_utf16.output_len(), 3);
239 let buf3: [u16; 3] = encoder_utf16.const_eval();
240 assert_eq!(buf3, [b'a' as u16, b'b' as u16, b'c' as u16]);
241
242 let encoder_utf16_z = Encode(
243 "hi",
244 Utf16Encoder {
245 nul_terminated: true,
246 },
247 );
248 assert_eq!(encoder_utf16_z.output_len(), 3);
249 let buf4: [u16; 3] = encoder_utf16_z.const_eval();
250 assert_eq!(buf4, [b'h' as u16, b'i' as u16, 0]);
251
252 let encoder_unicode = Encode(
254 "你好",
255 Utf16Encoder {
256 nul_terminated: false,
257 },
258 );
259 let len = encoder_unicode.output_len();
260 assert_eq!(len, 2);
261
262 let encoder_empty = Encode(
264 "",
265 Utf8Encoder {
266 nul_terminated: false,
267 },
268 );
269 assert_eq!(encoder_empty.output_len(), 0);
270 }
271}