#generate #doctest #quote #syn #config-file

flexgen

一个灵活且简单的基于quote的代码生成器,用于创建美观的Rust代码

10 个不稳定版本 (3 个破坏性更新)

0.4.5 2022年4月22日
0.4.4 2022年4月20日
0.3.0 2022年4月19日
0.2.1 2022年4月19日
0.1.0 2022年3月30日

#1038 in 开发工具

MIT/Apache

120KB
2.5K SLoC

flexgen

Crate Docs

一个灵活且简单的基于quote的代码生成器,用于创建美观的Rust代码

为什么?

Rust 有两种类型的宏,它们都很受欢迎,但并不总是最佳选择。它们可能会影响构建性能,并使源代码更难以阅读和研究。常规宏难以执行比简单变量替换更复杂的操作,而通过 proc-macro 使用 quote 不允许在文档块中进行变量插值(有关解决方案,请参阅 quote-doctest)。

代码生成也不是完美的。它创建了过多的代码,这些代码很可能是高度重复的,从而产生“噪声”。然而,也很有必要有一个完整的源代码集合,并且可以通过文档轻松访问。由于我们可以在提前生成,它对性能的影响与常规Rust代码相同。

正确的解决方案可能取决于使用场景。我个人认为,宏更适合编写非常简单的重复代码或非常复杂的事情,没有它们就难以完成或不可能完成的事情。代码生成更加专业化,但非常适合生成大量包装代码,尤其是对于每个类型略有不同且需要更多逻辑来处理的代码(特别是在doctests中)。

示例

查看“fibonacci”示例可能最简单: 目录

  • fib.rs - 生成的文件
  • flexgen.toml - 配置文件
  • main.rs - 生成 fib.rs 的源文件

自行运行

  1. 切换到 examples/basic 目录
  2. 删除现有的 fib.rs 文件
  3. 运行: cargo run --example basic
  4. 编译新的 fib.rs 文件:rustc fib.rs -C opt-level=3
  5. 运行它:./fib

用法

  1. 创建一个新的二进制crate(flexgen 是一个库,不是一个二进制crate)

  2. 编辑 Cargo.toml 并添加任何需要的依赖(至少需要 flexgen,但你可能还需要 quote 以及可能的 quote-doctest

[dependencies]
flexgen = "0.4"
  1. 编辑你的 main.rs 并添加一个或多个实现 CodeFragment 的代码片段。一个片段包含多少代码是一个试错的过程,但通常是一个“一件事”(即一个函数)。有关更多详细信息,请参阅上面的示例。
// main.rs

use flexgen::var::TokenVars;
use flexgen::{import_vars, CodeFragment, Error};
use quote::quote;

struct HelloWorld;

impl CodeFragment for HelloWorld {
    fn generate(&self, vars: &TokenVars) -> Result<TokenStream, Error> {
        import_vars! { vars => hello };

        Ok(quote! {
            fn main() {
                println!("{hello} world!");
            }
        })
    }
}
  1. 创建和编辑 flexgen.toml

注意:所有可能的选项都可以在测试代码中找到,请参见 这里

# flexgen.toml

[fragment_lists]
hello = [ "hello_world" ]

[files.hello]
path = "hello.rs"
fragment_list = "hello"

[files.hello.vars]
hello = "Hello"
  1. main.rs 文件中添加一个 main 函数
// main.rs

use flexgen::config::Config;
use flexgen::{register_fragments, Error, CodeGenerator};

fn main() -> Result<(), Error> {
    // Register all your code fragments
    let fragments = register_fragments!(HelloWorld);
    // Read in the configuration from our flexgen.toml file
    let config = Config::from_default_toml_file()?;
    // Create a new code generator from our fragments and config
    let gen = CodeGenerator::new(fragments, config)?;
    // Generate our 'hello.rs' file
    gen.generate_files()
}
  1. 执行你的二进制文件以生成代码
cargo run

许可证

此项目可以选择性地根据以下任一许可证进行许可:

依赖项

~4MB
~75K SLoC