4个版本 (2个重大变更)
0.3.0 | 2024年5月24日 |
---|---|
0.2.1 | 2024年4月5日 |
0.2.0 | 2024年3月2日 |
0.1.0 | 2024年1月29日 |
#150 in 过程宏
在 2 crates 中使用
18KB
414 行
Stageleft
Stageleft将阶段性编程的魔力带给Rust,使编写具有类型安全逻辑和高级API的宏变得容易,这些API可以在底层生成高效的代码。示例
Stageleft使编写类型安全的代码生成器变得容易。例如,考虑一个将数字提高到幂次的函数,但幂次在编译时已知。然后,我们可以将幂次编译成反复平方基数。我们可以为此实现一个阶段性程序
use stageleft::{q, BorrowBounds, IntoQuotedOnce, Quoted, RuntimeData};
#[stageleft::entry]
fn raise_to_power(_ctx: BorrowBounds<'_>, value: RuntimeData<i32>, power: u32) -> impl Quoted<i32> {
if power == 1 {
q!(value).boxed()
} else if power % 2 == 0 {
let half_result = raise_to_power(_ctx, value, power / 2);
q!({
let v = half_result;
v * v
})
.boxed()
} else {
let half_result = raise_to_power(_ctx, value, power / 2);
q!({
let v = half_result;
(v * v) * value
})
.boxed()
}
}
宏 q!(...)
将代码 引用,这意味着它将被拼接到最终生成的代码中。我们可以将未知基数作为运行时参数(RuntimeData<i32>
),但幂次在编译时已知,所以我们将其作为 u32
。在这种情况下,_ctx
参数未使用,因为我们正在返回任何借用数据(有关详细信息,请参阅 stageleft::entry
)。boxed
API 允许我们从同一函数返回不同的拼接代码,而返回类型 impl Quoted<i32>
告诉编译器该函数将返回一个评估为 i32
的代码片段。我们可以像调用常规Rust宏一样调用这个阶段性函数
let result = raise_to_power!(2, 5);
assert_eq!(result, 1024);
但是,如果我们展开宏,我们可以看到代码已经被优化(为了简洁起见进行了简化)
{
fn expand_staged(value: i32) -> i32 {
let v = {
let v = {
let v = value;
v * v // 2^2
};
(v * v) * value // 2^5
};
v * v // 2^10
}
expand_staged(2)
}
设置
Stageleft 需要特定的工作空间设置,因为任何使用 Stageleft 的 crate 都必须有一个支持性宏 crate(其内容将被自动生成)。对于一个名为 foo
的 crate,您还需要一个辅助 crate foo_macro
。
主 crate foo
需要以下 Cargo.toml
[package]
// ...
[dependencies]
stageleft = "0.1.0"
foo_macro = { path = "../foo_macro" }
[build-dependencies]
stageleft_tool = "0.1.0"
辅助 crate 应该具有以下 Cargo.toml
[package]
name = "foo_macro"
// ...
[lib]
proc-macro = true
path = "../foo/src/lib.rs"
[features]
default = ["macro"]
macro = []
[dependencies]
// all dependencies of foo
[build-dependencies]
stageleft_tool = "0.1.0"
接下来,您需要为您的两个 crate 设置 build.rs
脚本。
在 foo
中
fn main() {
stageleft_tool::gen_final!();
}
以及在 foo_macro
中
use std::path::Path;
fn main() {
stageleft_tool::gen_macro(Path::new("../foo"), "foo");
}
依赖项
~3.5MB
~71K SLoC