External Publication
Visit Post

Sized (or Sizeable) str, e.g. str<const N: usize>

Rust Internals [Unofficial] April 30, 2026
Source

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

Loading comments...