Process external files in const fn: no build.rs, no proc macros, no binary bloat
Here’s a fun Rust trick I’ve been experimenting with for embedded work:
You can use include_bytes!() inside a const fn, to process file contents at compile time, and keep only the final result in your binary.
No build.rs. No proc macros. No runtime cost.
Minimal example
const fn sum_u16s() -> u128 {
let data: &[u8; 8] = include_bytes!("data.bin");
assert!(data.len() % 2 == 0);
let mut i = 0;
let mut acc: u128 = 0;
while i < data.len() {
// interpret two bytes as little-endian u16
let value = (data[i] as u16)
| ((data[i + 1] as u16) << 8);
acc += value as u128;
i += 2;
}
acc
}
static SUM: u128 = sum_u16s();
What’s happening:
include_bytes!()reads the file at compile time.- The loop runs entirely in const evaluation.
- The compiler computes SUM during compilation.
- Only the u128 result is stored in the final binary.
If you remove the static SUM, the file contributes zero bytes to the binary (release build). It’s just compile-time input.
Why this is interesting
For embedded Rust, this effectively gives you a tiny compile-time asset pipeline:
- Read raw data files (audio, lookup tables, calibration data, etc.)
- Validate them
- Transform them (even some audio compression)
- Materialize only the final representation you actually need
And you only pay flash space for what you explicitly store.
It’s surprisingly powerful and it’s all stable Rust today.