How to convert string to hex at compile time?

Aim: convert string "1A2B3344" to hex array [1Au8, 2Bu8, 33u8, 44u8] at compile time, and that string may be stored in one file.

For now, hex crate and hex-literal crate provide the functionality to convert hex string to hex array. However, these two crates can't achieve my goal because:

  • hex crate provides decode by hex::decode function, which is not a const fn, so we can't do it at compile time.
  • hex-literal crate provides decode by hex macro, which only accepts string literal, so I can't do something like
const hex_array: &[u8] = {
    let hex_string = include_str!("path/to/hex_file");
    hex_literal::hex!(hex_string)
}

Assuming you control the file,

const hex_array: &[u8] = &u32::to_be_bytes(include!("hex_file"));

where hex_file contains

0x1A2B3344

would be one way.

This hex string may be very long, 1A2B3344 is just an example. Hex that larger than u64 can't be done in this way.

You could write a build script that combines the hex-literal macro and your file.

On the nightly compiler, you could do something like this:


#![feature(const_panic, min_const_generics)]

const fn hex_to_nybble(i:u8)->u8 {
    match i as char {
        '0' => 0,
        '1' => 1,
        '2' => 2,
        '3' => 3,
        '4' => 4,
        '5' => 5,
        /* ... */
        _ => panic!("invalid char")
    }
}

const fn hex_to_byte(h: u8, l:u8)->u8 { (hex_to_nybble(h) << 4) + hex_to_nybble(l) }

const fn hex_to_arr<const N:usize>(i_buf: &[u8])->[u8;N] {
    let mut o_buf = [0;N];
    let mut i:usize = 0;
    let mut o:usize = 0;
    while o<N {
        o_buf[o] = hex_to_byte(i_buf[i], i_buf[i+1]);
        o += 1;
        i += 2;
    }
    o_buf
}

const INFILE: &[u8] = b"12341234";
const FROMHEX_LEN:usize = INFILE.len()/2;
const FROMHEX: &[u8] = &hex_to_arr::<FROMHEX_LEN>(INFILE);

(Playground)

3 Likes

And for stable Rust, I've released a helper crate that allows chaining custom macros with some of the built-in ones:

2 Likes