12 unstable releases (3 breaking)
0.4.0 | Jan 9, 2020 |
---|---|
0.3.6 | Dec 7, 2019 |
0.3.4 | Nov 20, 2019 |
0.3.3 | Sep 27, 2019 |
0.1.0 | Jul 30, 2019 |
#591 in Procedural macros
41KB
836 lines
Sourcegen
Source generator
Sourcegen is a toolkit for in-place source code generation in Rust.
In-place source code generation is like a procedural macro in Rust, but with a difference that it is expanded before Rust code is compiled. For example, one use-case could be generating data types based on an external definition.
You start with the following code:
#[sourcegen::sourcegen(generator = "json-schema", schema = "widget.json")]
struct Widget;
Then, you run a special tool that is built on top of the sourcegen-cli
crate:
cargo run --package json-schema-sourcegen
Which expands the code above into something like (this assumes that widget.json
schema defines a data type with
two fields, name
and weight
:
#[sourcegen::sourcegen(generator = "json-schema", schema = "widget.json")]
struct Widget {
/// Name of the widget
name: String,
/// Weight of the widget
weight: usize,
}
Next time you run the tool, it would not change the code as it is already in it's correct form.
Creating a Tool
In the current form, you build your own tool on top of the sourcegen_cli::run_tool
entry point. This function takes
a number of input parameters and a list of source generators implementations.
Source generators are similar to procedural macros, they take syntax as an input and return token stream as an output.
Input to source generators use syn
crate for representing syntax trees. Returned tokens are
rendered by generators into the source code and formatted via rustfmt
.
Rationale
What are the benefits of generating source code this way compared to using procedural macros or generating code during
the build via build.rs
?
Advantages over procedural macros:
- Does not take compilation time.
- Compilation does not depend on original metadata used for generation.
- You have source code to look at. This is especially useful when generated code are data types of some sort.
- The generator code can depend on the generated types (bootstrapping).
Advantages over build.rs
source generation:
- Does not take compilation time.
- Compilation does not depend on original metadata used for generation.
- More flexible setup: can generate code piecemeal directly where it is used.
- No need to include generated code via
include!
or other means (build.rs
cannot write to sources).
However, there are also some disadvantages:
- Potential desynchronization between source of truth metadata and source code.
- If source generators depend on their own output, harder to work on the source generators themselves (if they generate invalid code, recovering might require reverting the generated code via source control).
- Too magical.
Dependencies
~4–12MB
~174K SLoC