arrayvec
arrayvec copied to clipboard
Const constructor for strings via a macro?
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.
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
}
What do you think of #205? We could skip the ArrayVec parts since they are quite limited
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.