Skip to content

Const constructor for strings via a macro? #204

Description

@aldanor

Wonder if it's possible in theory (scratched my head at it for a bit but couldn't quite figure all the details), to have something like:

const S: ArrayString<10> = array_string!("foo");

This would be super cool as it would allow pre-initialized array-strings in const contexts which is currently not doable.

// Without macros, as of this moment, don't think it's possible.
// It's most likely (?) doable via a proc-macro (the problem there will be that we don't know the cap), and may also require adding an extra 'raw' const constructor.

Activity

  1. bluss commented on Nov 7, 2021

    @bluss
    Owner

    I had to try, and it works today. Everything PoC, but our Rust const language is powerful enough to do this in stable Rust.
    It's maybe chance that I started with "byte string", it works fine in const as from_str(&str) too.

    What's your use case? Since you'd presumably want a mutable string, I'm unsure about the purpose. With that said, an arraystring is just barely more compact than a string literal (u32 length + data means it's 4 bytes + string length as inline data), so could be useful as a non-mutable thing too?

    const S1: ArrayString<10> = ArrayString::from_byte_string_const(b"hi there");
    const S2: ArrayString<10> = ArrayString::from_byte_string_const(b"hi there this is too long");  // compile error (panic)
    const S3: ArrayString<10> = ArrayString::from_byte_string_const(b"Inv\xAAlid");  // compile error panic
    
    
    pub const fn from_byte_string_const<const N: usize>(b: &[u8; N]) -> Self {
        assert_capacity_limit_const!(CAP);
        if N > CAP {
            panic!("from_byte_string_const: input too long");
        }
        let len = N;
        let mut vec = Self::new_const();
        let mut i = 0;
        while i < len {
            let byte = b[i];
            if byte >= 128 {
                panic!("from_byte_string_const: only supports ascii at this time");
            }
            vec.xs[i] = MaybeUninit::new(byte);
            i += 1;
        }
        // Safety: we know N <= CAP
        vec.len = len as u32;
        vec
    }
    
    
    pub const fn from_str_const(s: &str) -> Self {
        let b = s.as_bytes();
        assert_capacity_limit_const!(CAP);
        let len = b.len();
        let mut vec = Self::new_const();
        let mut i = 0;
        while i < len {
            if i >= CAP {
                panic!("from_str_const: input too long");
            }
            let byte = b[i];
            vec.xs[i] = MaybeUninit::new(byte);
            i += 1;
        }
        // Safety: we know len <= CAP
        vec.len = len as u32;
        vec
    }
  2. bluss commented on Nov 7, 2021

    @bluss
    Owner

    What do you think of #205? We could skip the ArrayVec parts since they are quite limited

  3. aldanor commented on Nov 7, 2021

    @aldanor
    Author

    What's your use case? Since you'd presumably want a mutable string, I'm unsure about the purpose.

    In my particular case, storing a bunch of hardcoded (immutable) "known objects" in a const context that (other than ArrayString, as of now), can be const-constructed, so they can be checked against later in many other contexts.

    Yes, it's possible to use lazy-static and all, but having it all clean and const would be awesome.

    We could skip the ArrayVec parts since they are quite limited

    Yep, agreed.

  4. qinghon commented on Jun 2, 2026

    @qinghon

    any update for this feature ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions