Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Const constructor for strings via a macro? #204

Open
aldanor opened this issue Nov 6, 2021 · 3 comments · May be fixed by #205
Open

Const constructor for strings via a macro? #204

aldanor opened this issue Nov 6, 2021 · 3 comments · May be fixed by #205

Comments

@aldanor
Copy link

aldanor commented Nov 6, 2021

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.

@bluss
Copy link
Owner

bluss commented Nov 7, 2021

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
}

@bluss
Copy link
Owner

bluss commented Nov 7, 2021

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

@aldanor
Copy link
Author

aldanor commented Nov 7, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants