#[doc = crate::_tags!(code)]
#[doc = crate::_doc_location!("sys/mem/view")]
#[macro_export]
#[cfg_attr(cargo_primary_package, doc(hidden))]
macro_rules! _const_join {
(bytes:) => { &[] };
(bytes: $bytes:expr $(,)?) => { $crate::const_join!(bytes_as_slice: $bytes) };
(bytes: $($bytes: expr),+ $(,)?) => {{
const SLICES: &[&[u8]] = &[$( $crate::const_join!(bytes_as_slice: $bytes) ),+];
const LEN: usize = $crate::ArrayFrom(SLICES).len();
&$crate::ArrayFrom(SLICES).to_array::<LEN>()
}};
(bytes_repeated: $bytes:expr, $num:expr $(,)?) => {{
const SLICE: &[u8] = $crate::const_join!(bytes_as_slice: $bytes);
const NUM: usize = $num;
const LEN: usize = SLICE.len() * NUM;
const fn repeated() -> [u8; LEN] {
let (mut out, mut i) = ([0u8; LEN], 0);
while i < NUM {
$crate::Slice::<u8>::copy_array_at(&mut out, SLICE, i * SLICE.len()); i += 1;
}
out
}
&repeated()
}};
(bytes_separated: $sep:expr; $first:expr, $($rest:expr),+ $(,)?) => {{
const fn join() -> [u8; LEN] {
let (mut out, mut pos, mut i) = ([0u8; LEN], 0, 0);
while i < $first.len() { out[pos] = $first[i]; pos += 1; i += 1; }
$(
let mut j = 0; while j < $sep.len() { out[pos] = $sep[j]; pos += 1; j += 1; }
let mut k = 0; while k < $rest.len() { out[pos] = $rest[k]; pos += 1; k += 1; }
)+
out
}
const SEP: &[u8] = $sep;
const LEN: usize = $first.len() $(+ SEP.len() + $rest.len())+;
&join()
}};
(bytes_as_slice: $bytes: expr) => {{
const LEN: usize = $crate::ArrayFrom($bytes).len();
&$crate::ArrayFrom($bytes).to_array::<LEN>()
}};
(str: ) => { "" };
(str: $A:expr $(,)?) => { $A };
(str: $A:expr, $B:expr, $($rest:expr),+ $(,)?) => {
$crate::const_join!(str: $A, $crate::const_join!(str: $B $(, $rest)+))
};
(str: $A:expr, $B:expr $(,)?) => {{
const fn combined() -> [u8; LEN] {
let mut out = [0u8; LEN];
$crate::Slice::<u8>::copy_array_at(&mut out, A.as_bytes(), 0);
$crate::Slice::<u8>::copy_array_at(&mut out, B.as_bytes(), A.len());
out
}
const A: &str = $A;
const B: &str = $B;
const LEN: usize = A.len() + B.len();
const RESULT: &[u8] = &combined();
$crate::Str::__utf8_bytes_to_str(RESULT)
}};
(str_repeated: $A:expr, $count:expr $(,)?) => {{
const fn repeated() -> [u8; LEN] {
let mut out = [0u8; LEN];
let mut i = 0;
while i < COUNT {
$crate::Slice::<u8>::copy_array_at(&mut out, A.as_bytes(), i * A.len());
i += 1;
}
out
}
const A: &str = $A;
const COUNT: usize = $count;
const LEN: usize = A.len() * COUNT;
const REPEATED: &[u8] = &repeated();
$crate::Str::__utf8_bytes_to_str(REPEATED)
}};
(str_separated: $sep:expr; $first:expr, $($rest:expr),+ $(,)?) => {{
const fn join() -> [u8; LEN] {
let (mut out, mut pos, mut i) = ([0u8; LEN], 0, 0);
let first = $first.as_bytes();
while i < first.len() { out[pos] = first[i]; pos += 1; i += 1; }
$(
let mut j = 0; let sep = $sep.as_bytes();
while j < sep.len() { out[pos] = sep[j]; pos += 1; j += 1; }
let mut k = 0; let rest = $rest.as_bytes();
while k < rest.len() { out[pos] = rest[k]; pos += 1; k += 1; }
)+
out
}
const SEP: &str = $sep;
const LEN: usize = $first.len() $(+ SEP.len() + $rest.len())+;
const RESULT: &[u8] = &join();
$crate::Str::__utf8_bytes_to_str(RESULT)
}};
}
#[doc(inline)]
pub use _const_join as const_join;
#[cfg(test)]
mod tests {
#![allow(unused)]
use crate::{const_assert, const_join};
#[test]
const fn join_bytes() {
const BASE: &[u8] = b"path/to";
const PART1: &[u8] = b"/foo";
const PART2: &[u8] = b"/bar";
const PATH: &[u8] = const_join!(bytes: BASE, PART1, PART2);
const_assert![eq_buf PATH, b"path/to/foo/bar"];
const REPEATED: &[u8] = const_join!(bytes_repeated: PART1, 3);
const_assert![eq_buf REPEATED, b"/foo/foo/foo"];
const PARTS: &[u8] = const_join!(bytes_separated: b"/"; b"path", b"to", b"file");
const_assert!(eq_buf PARTS, b"path/to/file");
}
#[test]
const fn join_bytes_mixed() {
const ARR_ARR: &[u8] = const_join!(bytes: [1, 2], [3, 4]);
const_assert!(eq_buf ARR_ARR, &[1,2,3,4]);
const ARR_SLI: &[u8] = const_join!(bytes: [1, 2], &[3, 4]);
const_assert!(eq_buf ARR_SLI, &[1,2,3,4]);
const ARR_LIT: &[u8] = const_join!(bytes: [1, 2, 3], 4);
const_assert!(eq_buf ARR_LIT, &[1,2,3,4]);
const STR_ARR_LIT_SLI: &[u8] = const_join!(bytes: "01", [1, 2], 3, &[4]);
const_assert!(eq_buf STR_ARR_LIT_SLI, &[48,49,1,2,3,4]);
}
#[test]
#[cfg(feature = "term")]
const fn join_bytes_ansi() {
use crate::Ansi;
const ANSI0: &[u8] = const_join!(bytes: Ansi::BOLD);
const_assert!(eq_buf & [27, 91, 49, 109], ANSI0);
const ANSI1: &[u8] = const_join!(bytes: Ansi::BOLD, Ansi::ITALIC);
const_assert![eq_buf & [27, 91, 49, 109, 27, 91, 51, 109], ANSI1];
}
#[test]
const fn join_str() {
const BASE: &str = "path/to";
const PART1: &str = "/foo";
const PART2: &str = "/bar";
const PATH: &str = const_join!(str: BASE, PART1, PART2);
const_assert![eq_str PATH, "path/to/foo/bar"];
const REPEATED: &str = const_join!(str_repeated: PART1, 3);
const_assert![eq_str REPEATED, "/foo/foo/foo"];
const PARTS: &str = const_join!(str_separated: "/"; "path", "to", "file");
const_assert!(eq_str PARTS, "path/to/file");
}
}