Skip to main content

const_util/
concat.rs

1//! Functions for concatenating slices
2
3use crate::Const;
4
5struct TwoValues<A, B>(A, B);
6impl<'a, T: ?Sized + 'a, A: Const<Type = &'a T>, B: Const<Type = &'a T>> Const for TwoValues<A, B> {
7    type Type = &'a [&'a T];
8    const VALUE: Self::Type = &[A::VALUE, B::VALUE];
9}
10/// Concats two `str`s into a single `&'static str` at compile time
11pub const fn concat_strs2<'a, Lhs: Const<Type = &'a str>, Rhs: Const<Type = &'a str>>(
12) -> &'static str {
13    concat_strs::<TwoValues<Lhs, Rhs>>()
14}
15
16/// Concats two `[u8]`s into a single `&'static [u8]` at compile time
17pub const fn concat_bytes2<'a, Lhs: Const<Type = &'a [u8]>, Rhs: Const<Type = &'a [u8]>>(
18) -> &'static [u8] {
19    concat_bytes::<TwoValues<Lhs, Rhs>>()
20}
21
22/// Concats a collection of `&str`s into a single `&'static str` at compile time.
23///
24/// # Example
25/// ```
26/// use const_util::{Const, concat::concat_strs};
27/// struct MyStrings;
28/// impl Const for MyStrings {
29///     type Type = &'static [&'static str];
30///     const VALUE: Self::Type = &[
31///         "Odd",
32///         "Even",
33///         "Schmeven",
34///     ];
35/// }
36/// assert_eq!(
37///     concat_strs::<MyStrings>(),
38///     "OddEvenSchmeven",
39/// )
40/// ```
41pub const fn concat_strs<'a, Strs: Const<Type = &'a [&'a str]>>() -> &'static str {
42    struct ToBytes<C>(C);
43    impl<'a, C: Const<Type = &'a [&'a str]>> Const for ToBytes<C> {
44        type Type = &'a [&'a [u8]];
45        // SAFETY: https://doc.rust-lang.org/reference/type-layout.html#r-layout.str
46        const VALUE: Self::Type = unsafe {
47            let strs = crate::value_of::<C>();
48            core::slice::from_raw_parts(strs.as_ptr().cast(), strs.len())
49        };
50    }
51    match core::str::from_utf8(concat_bytes::<ToBytes<Strs>>()) {
52        Ok(s) => s,
53        Err(_) => unreachable!(),
54    }
55}
56
57macro_rules! generate_slice_concat {
58    ($T:ty, $input:ty, $default:expr) => {{
59        use generic_upper_bound as gub;
60        struct Concat<C>(C);
61        gub::impl_accept_upper_bound! {
62            impl{'a, C: Const<Type = &'a [&'a [$T]]>} Concat<C>;
63            const DESIRED_GENERIC: usize = {
64                let mut slices = crate::value_of::<C>();
65                let mut out = 0;
66                while let [first, rest @ ..] = slices {
67                    out += first.len();
68                    slices = rest;
69                }
70                out
71            };
72            const EVAL<const N: usize>: &'static [$T] = &{
73                let mut out = [const { $default }; N];
74                let mut out_slice: &mut [_] = &mut out;
75                let mut slices = crate::value_of::<C>();
76                while let [first, rest @ ..] = slices {
77                    let lhs;
78                    (lhs, out_slice) = out_slice.split_at_mut(first.len());
79                    crate::utils::copy_from_slice(first, lhs);
80                    slices = rest;
81                }
82                out
83            };
84        }
85        gub::eval_with_upper_bound::<Concat<$input>>()
86            .split_at(gub::desired_generic::<Concat<$input>>())
87            .0
88    }};
89}
90
91/// Concats a collection of `&[u8]`s into a single `&'static [u8]` at compile time.
92///
93/// # Example
94/// Analogous to [`concat_strs`].
95pub const fn concat_bytes<'a, Bytes: Const<Type = &'a [&'a [u8]]>>() -> &'static [u8] {
96    generate_slice_concat!(u8, Bytes, 0)
97}