1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
#![feature(const_fn, const_str_as_bytes, const_str_len, const_let, untagged_unions)] #[allow(unions_with_drop_fields)] pub const unsafe fn transmute<From, To>(from: From) -> To { union Transmute<From, To> { from: From, to: To, } Transmute { from }.to } pub const unsafe fn concat<First, Second, Out>(a: &[u8], b: &[u8]) -> Out where First: Copy, Second: Copy, Out: Copy, { #[repr(C)] #[derive(Copy, Clone)] struct Both<A, B>(A, B); let arr: Both<First, Second> = Both(*transmute::<_, &First>(a), *transmute::<_, &Second>(b)); transmute(arr) } #[macro_export] macro_rules! const_concat { ($a:expr, $b:expr) => {{ let bytes: &'static [u8] = unsafe { &$crate::concat::< [u8; $a.len()], [u8; $b.len()], [u8; $a.len() + $b.len()], >($a.as_bytes(), $b.as_bytes()) }; unsafe { $crate::transmute::<_, &'static str>(bytes) } }}; ($a:expr, $($rest:expr),*) => {{ const TAIL: &str = const_concat!($($rest),*); const_concat!($a, TAIL) }}; ($a:expr, $($rest:expr),*,) => { const_concat!($a, $($rest),*); }; } #[cfg(test)] mod tests { #[test] fn top_level_constants() { const SALUTATION: &str = "Hello"; const TARGET: &str = "world"; const GREETING: &str = const_concat!(SALUTATION, ", ", TARGET, "!"); const GREETING_TRAILING_COMMA: &str = const_concat!(SALUTATION, ", ", TARGET, "!",); assert_eq!(GREETING, "Hello, world!"); assert_eq!(GREETING_TRAILING_COMMA, "Hello, world!"); } }