use core::marker::PhantomData;
use core::mem::ManuallyDrop;
pub trait ConstStr {
const VALUE: &'static str;
}
#[allow(nonstandard_style)]
pub struct StrLen<const N: usize>;
impl<Str, const LEN: usize> ConstStr for (StrLen<LEN>, Str)
where
Str: StringBuffer,
{
const VALUE: &'static str = {
struct StaticBuffer<T: StringBuffer, const N: usize>(PhantomData<T>);
impl<T: StringBuffer, const N: usize> StaticBuffer<T, N> {
const BYTES: [u8; N] = unsafe {
Cast::<T, N> {
encoded: ManuallyDrop::new(T::BYTES),
}
.array
};
}
unsafe { core::str::from_utf8_unchecked(&StaticBuffer::<Str, LEN>::BYTES) }
};
}
union Cast<T: StringBuffer, const N: usize> {
encoded: ManuallyDrop<T::Type>,
array: [u8; N],
}
pub unsafe trait StringBuffer {
type Type: 'static;
const BYTES: Self::Type;
}
pub struct Char1Byte<const CH: char>;
pub struct Char2Byte<const CH: char>;
pub struct Char3Byte<const CH: char>;
pub struct Char4Byte<const CH: char>;
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
const TAG_THREE_B: u8 = 0b1110_0000;
const TAG_FOUR_B: u8 = 0b1111_0000;
unsafe impl<const CH: char> StringBuffer for Char1Byte<CH> {
type Type = [u8; 1];
const BYTES: Self::Type = [CH as u8];
}
unsafe impl<const CH: char> StringBuffer for Char2Byte<CH> {
type Type = [u8; 2];
const BYTES: Self::Type = [
((CH as u32 >> 6) & 0x1F) as u8 | TAG_TWO_B,
(CH as u32 & 0x3F) as u8 | TAG_CONT,
];
}
unsafe impl<const CH: char> StringBuffer for Char3Byte<CH> {
type Type = [u8; 3];
const BYTES: Self::Type = [
((CH as u32 >> 12) & 0x0F) as u8 | TAG_THREE_B,
((CH as u32 >> 6) & 0x3F) as u8 | TAG_CONT,
(CH as u32 & 0x3F) as u8 | TAG_CONT,
];
}
unsafe impl<const CH: char> StringBuffer for Char4Byte<CH> {
type Type = [u8; 4];
const BYTES: Self::Type = [
((CH as u32 >> 18) & 0x07) as u8 | TAG_FOUR_B,
((CH as u32 >> 12) & 0x3F) as u8 | TAG_CONT,
((CH as u32 >> 6) & 0x3F) as u8 | TAG_CONT,
(CH as u32 & 0x3F) as u8 | TAG_CONT,
];
}
unsafe impl StringBuffer for () {
type Type = ();
const BYTES: Self::Type = ();
}
#[repr(C)]
pub struct Concat2<A, B>(A, B);
unsafe impl<A, B> StringBuffer for (A, B)
where
A: StringBuffer,
B: StringBuffer,
{
type Type = Concat2<A::Type, B::Type>;
const BYTES: Self::Type = Concat2(A::BYTES, B::BYTES);
}
#[repr(C)]
pub struct Concat3<A, B, C>(A, B, C);
unsafe impl<A, B, C> StringBuffer for (A, B, C)
where
A: StringBuffer,
B: StringBuffer,
C: StringBuffer,
{
type Type = Concat3<A::Type, B::Type, C::Type>;
const BYTES: Self::Type = Concat3(A::BYTES, B::BYTES, C::BYTES);
}
#[repr(C)]
pub struct Concat4<A, B, C, D>(A, B, C, D);
unsafe impl<A, B, C, D> StringBuffer for (A, B, C, D)
where
A: StringBuffer,
B: StringBuffer,
C: StringBuffer,
D: StringBuffer,
{
type Type = Concat4<A::Type, B::Type, C::Type, D::Type>;
const BYTES: Self::Type = Concat4(A::BYTES, B::BYTES, C::BYTES, D::BYTES);
}
#[repr(C)]
pub struct Concat5<A, B, C, D, E>(A, B, C, D, E);
unsafe impl<A, B, C, D, E> StringBuffer for (A, B, C, D, E)
where
A: StringBuffer,
B: StringBuffer,
C: StringBuffer,
D: StringBuffer,
E: StringBuffer,
{
type Type = Concat5<A::Type, B::Type, C::Type, D::Type, E::Type>;
const BYTES: Self::Type = Concat5(A::BYTES, B::BYTES, C::BYTES, D::BYTES, E::BYTES);
}
#[repr(C)]
pub struct Concat6<A, B, C, D, E, F>(A, B, C, D, E, F);
unsafe impl<A, B, C, D, E, F> StringBuffer for (A, B, C, D, E, F)
where
A: StringBuffer,
B: StringBuffer,
C: StringBuffer,
D: StringBuffer,
E: StringBuffer,
F: StringBuffer,
{
type Type = Concat6<A::Type, B::Type, C::Type, D::Type, E::Type, F::Type>;
const BYTES: Self::Type = Concat6(A::BYTES, B::BYTES, C::BYTES, D::BYTES, E::BYTES, F::BYTES);
}