Constructing a string in a const function

As part of an IRC server I'm working on, I am trying to construct a constant &'static str using other constant strings in an effort to have one source of truth, and I'm having problems because stable const functions for manipulating not only strings, but also Options/Results are lacking. So far I have:

use crate::data::modes::membership_modes::{Item, CONSTS};
const PREFIX: &'static str = unsafe { std::str::from_utf8_unchecked(&assemble_prefix()) };
// ^ The value I'm actually trying to construct
const NUM_PREFIXES: usize = CONSTS.len();
const PREFIX_LENGTH: usize = 2 * NUM_PREFIXES + 2;

const fn assemble_prefix() -> [u8; PREFIX_LENGTH] {
    let mut prefix_bytes = [65u8; PREFIX_LENGTH];
    prefix_bytes[0] = b'(';
    prefix_bytes[NUM_PREFIXES + 1] = b')';
    let mut counter = 0;
    while counter < NUM_PREFIXES {
        let Item::StrRefStrRef((mode, prefix_symbol)) = CONSTS[counter].1;
        prefix_bytes[1 + counter] = mode.as_bytes()[0];
        prefix_bytes[2 + NUM_PREFIXES + counter] = prefix_symbol.as_bytes()[0];
        counter += 1;
    }
    prefix_bytes
}

(For context, CONSTS is a const &[(&'static str, Item)] and Item::StrRefStrRef, the only variant, contains a (&'static str, &'static str) - both of these are generated by a macro. The end result I need is a string of a '(' followed by all of the mode characters, a ')' and then all of the prefix_symbol characters.)

Needing unsafe bothers me, because the only reason I can't use the standard from_utf8 is because I can't unwrap it while still being const. (And I managed to avoid needing any other unsafe so far) Slightly less bothersome but still annoying is having to declare the length of the array upfront and then cherry-pick characters into the right places rather than building it up. There doesn't seem to be any way to construct it directly as a &str either.

Is there any way to improve this on stable or make it more idiomatic?

3 Likes

Thanks for the link, I didn't know that existed. It looks like it'd solve part of the problem I'm having, but I don't see how I could use it (or something similar) to do the equivalent of join, since from the look of the docs, those macros need all of the values named individually.

I'd rather say all values must be listed in one macro. But it's still looks clean: https://www.rustexplorer.com/b/ys6b30

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.