Lazy_static, HashMap and include_bytes

I have a situation where I want the debug build of a Rocket application to use StaticFiles to map a physical directory tree to an URL -- but I want the release build to put the static files into the binary.

First: Yes, I know about the rust-embed crate -- it's a really fantastic crate, but it does however not support our use-case; we need more control of exactly what ends up in the final binary.

I'm wondering if it's possible to do something akin to this:

#[cfg(not(debug_assertions))]
#[get("/static/<file..>")]
pub fn get_static_file(file: PathBuf) -> response::Result {
  let logo = include_bytes!("../static/img/logo.svg");
  lazy_static! {
    static ref HASHMAP: HashMap<&'static Path, &'static [u8]> = {
      let mut m = HashMap::new();
      m.insert("foo/bar/baz.js", logo);
      m
    };
  }

  // ... look up the path and return the content ..
}

The intent here is to:

  • At compile time, load a bunch of files using include_bytes!
  • Statically init a HashMap for mapping pathnames to content that was imported using include_bytes.

I get new and exciting errors like can't capture dynamic environment in a fn item. I get the help help: use the || { ... } closure form instead, but I'm not sure how to actually apply that.

There are other issues with this code, but I'm specifically wondering if there's a way to statically initialize the HashMap so the handler doesn't have to reinitialize for each call.

Ah, well that part was easy -- it's literally what it says; don't include_bytes in a function.

You can include_bytes!() in a function. What you can't is to reference local variable within the lazy_static! initializer. You can make it const LOGO: &[u8] = include_bytes!(...); since const is a compile-time constant and can be accessed within the global context.

1 Like