I have a static array initialized with some constant value:
static PROG_ROM: [u8; 850] = [0x12, 0x1d, ...];
I would like to instead load at compile-time the contents of a file into it. Sounds like a job for std::include_bytes!
, however, I have two problems with it:
The type of include_bytes!("foo.dat")
is &[u8; 850]
i.e. it is a reference. I need this to be a bonafide static array.
Even if there was an include_bytes_static!
macro with type [u8;850]
, I would have to use it like this:
static PROG_ROM: [u8; 850] = include_bytes_static!("foo.dat");
I.e. I would have to hardcode the length of the file. Instead, I would like to take the length from the length of the file contents.
So the ideal replacement for my code would be a macro to replace the whole definition, i.e. look something like this:
define_included_bytes!(PROG_ROM, "foo.dat")
and it would expand to
static PROG_ROM: [u8; 850] = [0x12, 0x1d, ...];
So how do I do this?
As Chayim Friedman pointed out you can easily define that proc macro yourself:
#[proc_macro]
pub fn define_included_bytes(token_stream: TokenStream) -> TokenStream {
let [ident, _comma, file] = &token_stream.into_iter().collect::<Vec<_>>()[..] else {
panic!("expected invocation: `define_included_bytes!(IDENTIFIER, \"file_name\");");
};
let file = file.to_string().trim_matches('\"').to_string();
let data: Vec<u8> = std::fs::read(&file).expect(&format!("File {:?} could not be read", file));
format!("const {ident}: [u8; {}] = {:?};", data.len(), data).parse().unwrap()
}
Obviously this is just a hacked together proof of concept and you should thouroughly check the tokens instead of just assuming they're correct.