Expand description
Rustifact
A seamless bridge between a build script and the main crate.
Motivation
When it comes to generating computationally intensive artifacts at compile time, we have many tools at our disposal: build scripts (build.rs), declarative macros (macro_rules!), procedural macros, and increasingly, const functions. Each of these methods, however, brings its own set of challenges.
Rustifact has been designed as a streamlined abstraction layer that simplifies the creation of build scripts that produce data for inclusion into the final binary.
Usage steps
-
Generate the required data in your build script.
-
(Optional*#) Implement the
ToTokenStreamtrait for each of your build script’s ‘exported’ types. -
Export your data with any combination of the
write_Xmacros. -
In the main part of your crate (within
src/) import your data withuse_symbols.
(*) ToTokenStream is implemented for primitive types (u8, i32, char, bool, …),
slices, array, Vec, and Option. This step is only necessary if you’re exporting your
own types. We expect to automate this step soon by providing suitable [#derive(...)] macros.
(#) These types should be implemented in a separate crate, so they’re usable from the build script and the main crate.
A simple example
build.rs
use rustifact::ToTokenStream;
fn generate_city_data() -> Vec<(String, u32)> {
let mut city_data: Vec<(String, u32)> = Vec::new();
for i in 1..=100 {
let city_name = format!("City{}", i);
let population = i * 1000; // Dummy population data
city_data.push((city_name, population));
}
city_data
}
fn main() {
let city_data = generate_city_data();
//
// Let's make city_data accessible from the main crate. We'll write it to
// a static array CITY_DATA where the type of each element is (&'static str, u32).
// Note that Strings are converted to static string slices by default.
//
rustifact::write_static_array!(CITY_DATA, (&'static str, u32), &city_data);
//
// We could have specified the dimension like so:
//rustifact::write_static_array!(CITY_DATA, (&'static str, u32) : 1, &city_data);
//
// When the dimension is unspecified (as above) the default is dimension 1.
}src/main.rs
rustifact::use_symbols!(CITY_DATA);
// The above line is equivalent to the declaration:
// static CITY_DATA: [(&'static str, u32); 1000] = [/*.. data from build.rs */];
fn main() {
for (name, population) in CITY_DATA.iter() {
println!("{} has population {}", name, population)
}
}Development status
Please note that Rustifact is in an early development stage. Overall, it is unlikely to cause unpleasant surprises, though there may be edge cases that haven’t yet been discovered. Some breaking changes may occur in the future, though we aim to preserve backward compatibility where possible.
Modules
- An implementation detail, exposing parts of external crates used by
rustifact.
Macros
- Import the given symbols (generated by the build script) into scope.
- Write an array or vector to an array getter function.
- Write a constant variable.
- Write an array to a const context.
- Write a collection of constants with a common type.
- Write a getter function for a heap-allocated variable.
- Write a collection of getter functions returning a common type.
- Write a static variable.
- Write an array to a static context.
- Write a collection of static variables with a common type.
- Write an array or vector to a vector getter function.
Traits
- Provides a flexible interface for converting Rust’s data types into their token stream representation. This trait is akin to
quote::ToTokens, with a similar design, but it serves a distinct purpose.