gpt4 book ai didi

rust - 推断调用包的名称以在过程宏中填充一个 doctest

转载 作者:行者123 更新时间:2023-11-29 07:58:26 29 4
gpt4 key购买 nike

我正在创建一个程序宏,它从一些配置文件自动生成一个库(这是一个寄存器布局,但这对问题并不重要)。

我希望库自动生成伴随自动库的文档,并包含应与 cargo test 一起运行的文档测试。现在,我已经实现了其中的大部分,但有一个问题我看不到解决方案。

假设我们有一个名为 my_lib 的库,我们在其中调用宏来填充它:

use my_macro_lib::hello;

hello!();

扩展为类似:

/// `foo` will always return `true`
/// ```
/// use my_lib;
/// assert!(my_lib::foo());
/// ```
pub fn foo() -> bool {
true
}

这将按预期运行 - cargo doc 将做正确的事情,cargo test 将按预期运行 doctests。

问题是,在这个例子中,use my_lib 被硬编码到 my_macro_lib 中,这显然是不可取的。

我如何创建一个宏来推断执行调用的 crate 的名称?

我尝试在过程宏中使用 macro_rules! 来扩展 $crate,但这违反了卫生规则。

最佳答案

您可以通过读取CARGO_PKG_NAME 环境变量来获取正在使用您的宏的箱子的名称。请注意,您必须通过阅读它 std::env (在你的宏的“运行时”)并且通过env! (当你的 proc macro crate 被编译时)。

#[proc_macro]
pub fn hello(input: TokenStream) -> TokenStream {
let crate_name = std::env::var("CARGO_PKG_NAME").unwrap();
let use_statement = format!("use {}::foo;", crate_name);

let output = quote! {
/// `foo` will always return `true`
/// ```
#[doc = #use_statement]
/// assert!(foo());
/// ```
pub fn foo() -> bool {
true
}
};

output.into()
}

这里有一些关于在文档注释中插入内容的复杂问题。像 ///#an_ident 这样的插值不起作用,因为文档注释以特殊方式解析。我们可以做到这一点的唯一方法是创建一个字符串并使用 #[doc = ...] 语法。这有点烦人,因为您必须在 quote! 调用之前创建字符串,但它有效。

但是,我认为这不能保证有效。目前 proc 宏可以访问所有环境(包括文件系统、网络...)。据我所知,proc 宏不能保证此访问权限,并且 proc 宏将来可能会被沙盒化。所以这个解决方案还不完美,但它现在有效(并且可能还会持续相当长的一段时间)。


另一种方法是让用户将箱子名称传递给您的宏:

hello!(my_lib);

如果您的宏在每个 crate 中只被调用一次,这可能是首选的解决方案。如果您的宏被多次调用,那么重复 crate 名称可能会很烦人。

关于rust - 推断调用包的名称以在过程宏中填充一个 doctest,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58606481/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com