const_str/__ctfe/
concat_bytes.rs

1pub 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/// Concatenates values into a byte slice.
107///
108/// The input type must be one of
109/// + [`u8`]
110/// + [`&[u8]`](slice)
111/// + [`[u8; N]`](array), [`&[u8; N]`](array)
112/// + [`&str`](str)
113///
114/// The output type is [`&[u8; _]`](array).
115///
116/// This macro is [const-context only](./index.html#const-context-only).
117///
118/// # Examples
119///
120/// ```rust
121/// const S1: &[u8; 7] = const_str::concat_bytes!(b'A', b"BC", [68, b'E', 70], "G");
122/// const S2: &[u8] = const_str::concat_bytes!(S1, "/123", 0u8);
123/// assert_eq!(S1, b"ABCDEFG");
124/// assert_eq!(S2, b"ABCDEFG/123\x00");
125/// ```
126///
127#[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}