Announcing the include_dir!() proc macro


#1

I spent the last couple days rewriting most of my include_dir crate to use proc macros via the awesome proc_macro_hack library and wanted to see what people think of it.

The standard library already has the include_str!() and include_bytes!() macros for compiling the contents of a single file into your binary, this crate just extends the idea to let people embed the contents of entire directories. This comes in handy when your application needs to bundle things like templates or static assets (e.g. images and textures) without needing to copy the files into an install directory.

For anyone interested, here’s an example of how you might use the include_dir!() macro to embed a crate’s source code inside itself.

#[macro_use]
extern crate include_dir;

use include_dir::Dir;
use std::path::Path;

static PROJECT_DIR: Dir = include_dir!(".");

// of course, you can retrieve a file by its full path
let lib_rs = PROJECT_DIR.get_file("src/lib.rs").unwrap();

// you can also inspect the file's contents
let body = lib_rs.contents_utf8().unwrap();
assert!(body.contains("SOME_INTERESTING_STRING"));

// you can search for files (and directories) using glob patterns
let glob = "**/*.rs";
for entry in PROJECT_DIR.find(glob).unwrap() {
    println!("Found {}", entry.path().display());
}

I’m still experimenting to see what things work and what doesn’t, so any feedback is appreciated :slightly_smiling_face:


#2

Just came across this. One lovely feature is that the macro operates relative to CARGO_MANIFEST_DIR, which means I can include code generated outside of src/ in build.rs (this is a necessity when trying to publish a crate, as cargo double checks src/ to verify nothing has changed in the meantime). I’ve been looking for a reliable way to do that and this seems like it’ll do the job nicely.


#3

Very cool! I wonder, is there a way to abstract over this macro and the actual filesystem? It would be great if I could read from the filesystem during development, and then include my assets in the binary for release.


#4

I assume this would be to allow something similar to “live updates”, similar to when you are developing a web app and the browser will refresh with the latest code on save?

You need to access a File’s contents using a getter instead of touching the field directly, so it shouldn’t be too hard to implement. It’d be pretty easy to add a live_updates feature to the crate which will conditionally read from the file system when cfg!(debug_assertions) is true.

Thanks for the idea!