Sized (or Sizeable) str, e.g. str<const N: usize>
daniel-pfeiffer:
Is there already a way of achieving this?
This method is fully const as of Rust 1.88 (for <[_]>::as_chunks). There are other methods for supporting earlier Rust versions (e.g. unsafely assume length in new_unchecked). [playground]
#[macro_export]
macro_rules! array_str { ($lit:literal) => { const {
const LIT: &str = $lit;
const LEN: usize = LIT.len();
$crate::ArrayStr::<LEN>::new(LIT).unwrap()
}}}
#[derive(Copy, Clone)]
pub struct ArrayStr<const LEN: usize>([u8; LEN]);
impl<const LEN: usize> ArrayStr<LEN> {
#[inline]
pub const fn new(s: &str) -> Option<&Self> {
if let ([bytes], []) = s.as_bytes().as_chunks() {
let ptr = core::ptr::from_ref::<[u8; LEN]>(bytes);
// SAFETY: Self is a transparent wrapper type
// SAFETY: bytes are UTF-8 and verified equal len
unsafe { ptr.cast::<Self>().as_ref() }
} else {
None
}
}
}
pub const BYTES: [u8; 5] = *b"hello";
pub const STR: ArrayStr<5> = *array_str!("hello");
I license any code I post here under SPDX: MIT-0 OR Apache-2.0.
Note that the Option::unwrap occurs atconst time due to the const block, so there is guaranteed no runtime overhead.
kpreid:
you can obtain the string length at compile time to derive the type from the literal value
I see I was ninjad while putting together my example. But! Note that your example could be unsound (EDIT: panicky) in the future if $:literal matchers can match custom type literals, as such a custom type could provide a .len() which does not match its deref-coercion to str. (This was more important before $:literal, when such macros had to take $:expr instead.)
Discussion in the ATmosphere