const_str/__ctfe/
concat_bytes.rs1pub struct ConcatBytesPart<T>(pub T);
2
3impl ConcatBytesPart<u8> {
4 pub const fn output_len(&self) -> usize {
5 1
6 }
7
8 pub const fn const_eval<const N: usize>(&self) -> [u8; N] {
9 crate::bytes::clone(&[self.0])
10 }
11}
12
13impl<const L: usize> ConcatBytesPart<&[u8; L]> {
14 pub const fn output_len(&self) -> usize {
15 L
16 }
17
18 pub const fn const_eval<const N: usize>(&self) -> [u8; N] {
19 crate::bytes::clone(self.0)
20 }
21}
22
23impl ConcatBytesPart<&[u8]> {
24 pub const fn output_len(&self) -> usize {
25 self.0.len()
26 }
27
28 pub const fn const_eval<const N: usize>(&self) -> [u8; N] {
29 crate::bytes::clone(self.0)
30 }
31}
32
33impl<const L: usize> ConcatBytesPart<[u8; L]> {
34 pub const fn output_len(&self) -> usize {
35 L
36 }
37
38 pub const fn const_eval<const N: usize>(&self) -> [u8; N] {
39 crate::bytes::clone(&self.0)
40 }
41}
42
43impl ConcatBytesPart<&str> {
44 pub const fn output_len(&self) -> usize {
45 self.0.len()
46 }
47
48 pub const fn const_eval<const N: usize>(&self) -> [u8; N] {
49 crate::bytes::clone(self.0.as_bytes())
50 }
51}
52
53pub struct ConcatBytes<'a>(pub &'a [&'a [u8]]);
54
55impl ConcatBytes<'_> {
56 pub const fn output_len(&self) -> usize {
57 let parts = self.0;
58 let mut sum = 0;
59 let mut i = 0;
60 while i < parts.len() {
61 sum += parts[i].len();
62 i += 1;
63 }
64 sum
65 }
66
67 pub const fn const_eval<const N: usize>(&self) -> [u8; N] {
68 let mut buf = [0; N];
69 let mut pos = 0;
70
71 macro_rules! push {
72 ($x:expr) => {
73 buf[pos] = $x;
74 pos += 1;
75 };
76 }
77
78 let parts = self.0;
79 let mut i = 0;
80 while i < parts.len() {
81 let part = parts[i];
82 let mut j = 0;
83 while j < part.len() {
84 push!(part[j]);
85 j += 1;
86 }
87 i += 1;
88 }
89
90 assert!(pos == N);
91 buf
92 }
93}
94
95#[doc(hidden)]
96#[macro_export]
97macro_rules! __concat_bytes_part {
98 ($x: expr) => {{
99 const OUTPUT_LEN: usize = $crate::__ctfe::ConcatBytesPart($x).output_len();
100 const OUTPUT_BUF: [u8; OUTPUT_LEN] = $crate::__ctfe::ConcatBytesPart($x).const_eval();
101 const OUTPUT: &[u8] = &OUTPUT_BUF;
102 OUTPUT
103 }};
104}
105
106#[macro_export]
128macro_rules! concat_bytes {
129 ($($x: expr),+ $(,)?) => {{
130 const PARTS: &[&[u8]] = &[$( $crate::__concat_bytes_part!($x) ),+];
131 const OUTPUT_LEN: usize = $crate::__ctfe::ConcatBytes(PARTS).output_len();
132 const OUTPUT_BUF: [u8; OUTPUT_LEN] = $crate::__ctfe::ConcatBytes(PARTS).const_eval();
133 &OUTPUT_BUF
134 }};
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_concat_bytes() {
143 const S1: &[u8; 7] = concat_bytes!(b'A', b"BC", [68, b'E', 70], "G");
144 const S2: &[u8] = concat_bytes!(S1, "/123", 0u8);
145 assert_eq!(S1, b"ABCDEFG");
146 assert_eq!(S2, b"ABCDEFG/123\x00");
147
148 const S3: &[u8] = concat_bytes!(b"hello", b" ", b"world");
149 assert_eq!(S3, b"hello world");
150
151 const S4: &[u8] = concat_bytes!(b'x');
152 assert_eq!(S4, b"x");
153
154 const S5: &[u8] = concat_bytes!("test", b"123");
155 assert_eq!(S5, b"test123");
156
157 const ARR: [u8; 3] = [1, 2, 3];
158 const S6: &[u8] = concat_bytes!(ARR, [4, 5]);
159 assert_eq!(S6, &[1, 2, 3, 4, 5]);
160 }
161
162 #[test]
163 fn test_concat_bytes_runtime() {
164 let part_u8 = ConcatBytesPart(42u8);
166 assert_eq!(part_u8.output_len(), 1);
167 let buf: [u8; 1] = part_u8.const_eval();
168 assert_eq!(buf, [42]);
169
170 let arr: &[u8; 3] = b"abc";
171 let part_arr = ConcatBytesPart(arr);
172 assert_eq!(part_arr.output_len(), 3);
173 let buf_arr: [u8; 3] = part_arr.const_eval();
174 assert_eq!(buf_arr, [b'a', b'b', b'c']);
175
176 let slice: &[u8] = b"hello";
177 let part_slice = ConcatBytesPart(slice);
178 assert_eq!(part_slice.output_len(), 5);
179 let buf_slice: [u8; 5] = part_slice.const_eval();
180 assert_eq!(buf_slice, *b"hello");
181
182 let owned_arr: [u8; 2] = [1, 2];
183 let part_owned = ConcatBytesPart(owned_arr);
184 assert_eq!(part_owned.output_len(), 2);
185 let buf_owned: [u8; 2] = part_owned.const_eval();
186 assert_eq!(buf_owned, [1, 2]);
187
188 let str_part = ConcatBytesPart("test");
189 assert_eq!(str_part.output_len(), 4);
190 let buf_str: [u8; 4] = str_part.const_eval();
191 assert_eq!(buf_str, *b"test");
192
193 let parts: &[&[u8]] = &[b"hello", b"world"];
195 let concat = ConcatBytes(parts);
196 assert_eq!(concat.output_len(), 10);
197 let buf: [u8; 10] = concat.const_eval();
198 assert_eq!(&buf, b"helloworld");
199
200 let empty_parts: &[&[u8]] = &[];
201 let concat_empty = ConcatBytes(empty_parts);
202 assert_eq!(concat_empty.output_len(), 0);
203 let buf_empty: [u8; 0] = concat_empty.const_eval();
204 assert_eq!(&buf_empty, b"");
205
206 let multi_parts: &[&[u8]] = &[b"a", b"b", b"c"];
208 let concat_multi = ConcatBytes(multi_parts);
209 assert_eq!(concat_multi.output_len(), 3);
210 let buf_multi: [u8; 3] = concat_multi.const_eval();
211 assert_eq!(&buf_multi, b"abc");
212 }
213}