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 #[test]
183 fn test_encode() {
184 {
185 const S: &str = "abc你好";
186 const B1: &[u8; 9] = encode!(utf8, S);
187 const B2: &[u8] = encode!(utf8, S);
188 const B3: &[u8; 10] = encode_z!(utf8, S);
189 let mut ans = S.as_bytes().to_owned();
190 assert_eq!(B1, ans.as_slice());
191 assert_eq!(B2, B1);
192 ans.push(0);
193 assert_eq!(B3, ans.as_slice());
194 }
195 {
196 const S: &str = "abc你好𤭢";
197 const B1: &[u16; 7] = encode!(utf16, S);
198 const B2: &[u16; 8] = encode_z!(utf16, S);
199 let mut ans = S.encode_utf16().collect::<Vec<_>>();
200 assert_eq!(B1, ans.as_slice());
201 ans.push(0);
202 assert_eq!(B2, ans.as_slice());
203 }
204 }
205}