1#![no_std]
2
3#[doc(hidden)]
36pub const fn concated_size<const N: usize>(array: [&'static str; N], sep: &'static str) -> usize {
37 let mut n = if N == 0 { 0 } else { N - 1 } * sep.len();
38 let mut i = N;
39 loop {
40 if i <= 0 {
41 break;
42 }
43 i -= 1;
44 n += array[i].len();
45 }
46 n
47}
48
49#[doc(hidden)]
50pub const fn copy_bytes(src: &[u8], dest: &mut [u8], offset: usize) -> usize {
51 let mut i = 0;
52 let mut op = offset;
53 if !src.is_empty() {
54 loop {
55 assert!(dest[op] == b'\0');
56 dest[op] = src[i];
57 op += 1;
58 i += 1;
59 if i >= src.len() {
60 break;
61 }
62 }
63 }
64
65 op
66}
67
68#[doc(hidden)]
69pub const fn join_strings(inputs: &[&str], sep: Option<&str>, mut output: &mut [u8]) -> usize {
70 assert!(output.len() > 0);
71 let mut n = 0;
72 let mut op = 0;
73 loop {
74 op = copy_bytes(&inputs[n].as_bytes(), &mut output, op);
75
76 if n + 1 < inputs.len()
77 && let Some(sep) = sep
78 {
79 let s = sep.as_bytes();
80 op = copy_bytes(s, &mut output, op);
81 }
82
83 n += 1;
84 if n >= inputs.len() {
85 break;
86 }
87 }
88 op
89}
90
91#[macro_export]
99macro_rules! joined_array {
100 ($array:expr, $sep:expr) => {
101 const {
102 const SIZE: usize = $crate::concated_size($array, $sep);
103 $crate::joined_array!($array, $sep, SIZE)
104 }
105 };
106 ($array:expr, $sep:expr, $size:expr) => {
107 const {
108 const ARRAY_LEN: usize = $size;
109
110 let sep = $sep;
111 let sep = if sep.len() > 0 { Some(sep) } else { None };
112 let array = &$array;
113
114 let mut buffer = [0u8; ARRAY_LEN];
115 let next_position = $crate::join_strings(array, sep, &mut buffer);
116
117 assert!(next_position == ARRAY_LEN);
119 buffer
120 }
121 };
122
123}
124
125#[macro_export]
134macro_rules! declare_joined_str {
135 ($name:ident, $array:expr, $sep:expr) => {
136 const $name: &'static str = const {
137 const SIZE: usize = $crate::concated_size($array, $sep);
138 static STORAGE: [u8; SIZE] = $crate::joined_array!($array, $sep, SIZE);
139 if let Ok(v) = core::str::from_utf8(&STORAGE) {
141 v
142 } else {
143 panic!("joined array isn't a valid utf8 string");
144 }
145 };
146 };
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 const A: &'static str = "A";
154 const B: &'static str = "B";
155 const C: &'static str = "C";
156 const ARRAY_OF_STRINGS: [&'static str; 3] = [A, B, C];
157
158 #[test]
159 fn nested() {
160 declare_joined_str!(FOO, ARRAY_OF_STRINGS, ":");
161 const MORE_PARTS: [&'static str; 3] = ["<", FOO, ">"];
162 declare_joined_str!(MORE, MORE_PARTS, "");
163 assert_eq!(FOO, "A:B:C");
164 assert_eq!(MORE, "<A:B:C>");
165 }
166
167 #[test]
168 fn joined_array() {
169 let s = joined_array!(ARRAY_OF_STRINGS, "-");
170 assert_eq!(&s, b"A-B-C");
171 }
172}