3个版本
使用旧的Rust 2015
0.11.3 | 2017年3月1日 |
---|---|
0.11.2 | 2017年2月27日 |
0.11.1 |
|
0.11.0 | 2017年2月19日 |
1587在进程宏中排名
89,328每月下载量
在162个crate中使用了(直接使用5个)
62KB
736 行
Rust源代码的Nom解析器
无需Syntex依赖项解析Rust源代码,适用于与Macros 1.1一起使用。
专为快速编译时间设计。
syn
的编译时间(从头开始包括所有依赖项):6秒syntex/
quasi
/aster
堆栈的编译时间:60+秒
如果你在使用Macros 1.1时遇到问题,即使问题与syn无关,我也很乐意提供帮助。请在此存储库中提交工单。
与Macros 1.1一起使用
[dependencies]
syn = "0.11"
quote = "0.3"
[lib]
proc-macro = true
extern crate proc_macro;
use proc_macro::TokenStream;
extern crate syn;
#[macro_use]
extern crate quote;
#[proc_macro_derive(MyMacro)]
pub fn my_macro(input: TokenStream) -> TokenStream {
let source = input.to_string();
// Parse the string representation into a syntax tree
let ast = syn::parse_derive_input(&source).unwrap();
// Build the output, possibly using quasi-quotation
let expanded = quote! {
// ...
};
// Parse back to a token stream and return it
expanded.parse().unwrap()
}
完整示例
假设我们有一个以下简单的特质,它返回结构体中的字段数量
trait NumFields {
fn num_fields() -> usize;
}
基于syn
和quote
的完整的Macros 1.1实现如下所示
extern crate proc_macro;
use proc_macro::TokenStream;
extern crate syn;
#[macro_use]
extern crate quote;
#[proc_macro_derive(NumFields)]
pub fn num_fields(input: TokenStream) -> TokenStream {
let source = input.to_string();
// Parse the string representation into a syntax tree
let ast = syn::parse_derive_input(&source).unwrap();
// Build the output
let expanded = expand_num_fields(&ast);
// Return the generated impl as a TokenStream
expanded.parse().unwrap()
}
fn expand_num_fields(ast: &syn::DeriveInput) -> quote::Tokens {
let n = match ast.body {
syn::Body::Struct(ref data) => data.fields().len(),
syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"),
};
// Used in the quasi-quotation below as `#name`
let name = &ast.ident;
// Helper is provided for handling complex generic types correctly and effortlessly
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
quote! {
// The generated impl
impl #impl_generics ::mycrate::NumFields for #name #ty_generics #where_clause {
fn num_fields() -> usize {
#n
}
}
}
}
测试
Macros 1.1有一个限制,即你的进程宏crate必须只导出proc_macro_derive
函数,而且proc_macro_derive
进程宏不能在定义它们的crate中使用。这些限制可能在将来被取消,但到目前为止,它们使得编写测试比其他类型的代码要复杂一些。
特别是,您无法按照代码行的方式编写测试函数,例如:#[test] fn it_works() { ... }
。相反,您可以将测试放在一个tests
目录中,或者完全在另一个crate中。
此外,如果您的过程宏实现了特定的trait,那么该trait必须在过程宏之外单独的crate中定义。
作为一个具体的例子,假设您的过程宏crate名为my_derive
,并且它实现了名为my_crate::MyTrait
的trait。您的过程宏单元测试可以放在my_derive/tests/test.rs
中,或者放入一个单独的crate my_tests/tests/test.rs
中。无论哪种方式,测试代码可能如下所示
#[macro_use]
extern crate my_derive;
extern crate my_crate;
use my_crate::MyTrait;
#[test]
fn it_works() {
#[derive(MyTrait)]
struct S { /* ... */ }
/* test the thing */
}
调试
在开发过程宏时,查看生成的代码可能会有所帮助。使用cargo rustc -- -Zunstable-options --pretty=expanded
或cargo expand
子命令。
要显示使用您的过程宏的crate的展开代码,请在该crate中运行cargo expand
。要显示您的测试用例之一的展开代码,请运行cargo expand --test the_test_case
,其中最后一个参数是不带.rs
扩展名的测试文件名。
Brandon W Maister的这篇文档更详细地讨论了调试:[调试Rust的新自定义Derive系统](https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/)
可选功能
Syn将很多功能放在可选功能后面,以优化最常见的用例的编译时间。以下是可用的功能及其对编译时间的影响。依赖项包含在编译时间中。
功能 | 编译时间 | 功能 |
---|---|---|
(无) | 3秒 | Rust结构体、枚举和类型的AST表示的数据结构。 |
解析 | 6秒 | 解析包含结构体和枚举的Rust源代码到AST。 |
打印 | 4秒 | 将结构体和枚举的AST打印为Rust源代码。 |
解析,打印 | 6秒 | 这是默认选项。解析和打印Rust结构体和枚举。通常您想要为实现Macros 1.1自定义Derive实现此选项。 |
完整 | 4秒 | 表示所有可能的Rust代码的完整AST的数据结构。 |
完整,解析 | 9秒 | 将任何有效的Rust源代码解析到AST。 |
完整,打印 | 6秒 | 将AST转换为Rust源代码。 |
完整,解析,打印 | 11秒 | 解析和打印任何Rust语法。 |
许可证
根据以下许可证之一授权
- Apache许可证版本2.0(《LICENSE-APACHE》或http://www.apache.org/licenses/LICENSE-2.0)
- MIT许可证(《LICENSE-MIT》或http://opensource.org/licenses/MIT)
由您选择。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您提交的任何有意包含在本软件包中的贡献将以上述方式双许可,不附加任何额外条款或条件。
依赖项
~60KB