Example
Stageleft makes it easy to write type-safe code generators. For example, consider a function that raises a number to a power, but the power is known at compile time. Then, we can compile away the power into repeatedly squaring the base. We can implement a staged program for this:
use ;
The q!(...) macro quotes code, which means that it will be spliced into the final generated code. We can take in the unknown base as a runtime parameter (RuntimeData<i32>), but the power is known at compile time so we take it as a u32. The _ctx parameter is unused in this case, because we are returning any borrowed data (see stageleft::entry for more details). The .boxed() API allows us to return different pieces of spliced code from the same function, and the impl Quoted<i32> return type tells the compiler that the function will return a piece of code that evaluates to an i32. We can invoke this staged function just like a regular Rust macro:
let result = raise_to_power!;
assert_eq!;
But if we expand the macro, we can see that the code has been optimized (simplified for brevity):
Setup
Stageleft requires a particular workspace setup, as any crate that uses Stageleft must have an supporting macro crate (whose contents will be automatically generated). For a crate named foo, you will also need a helper crate foo_macro.
The main crate foo will need the following Cargo.toml:
[]
// ...
[]
= "0.1.0"
= { = "../foo_macro" }
[]
= "0.1.0"
The helper crate should have the following Cargo.toml:
[]
= "foo_macro"
// ...
[]
= true
= "src/lib.rs"
[]
= ["macro"]
= []
[]
// all dependencies of foo
[]
= "0.1.0"
Next, you will need to set up build.rs scripts for both of your crates.
In foo:
and in foo_macro:
use Path;
Finally, you will need to set up the lib.rs in these crates.
In foo, simply add stageleft::stageleft_crate!(foo_macro); at the top of the file.
In foo_macro, your lib.rs will only need to contain the following:
stageleft_macro_crate!;