Skip to content

Rust Macro #35

@jackalchenxu

Description

@jackalchenxu

Rust宏设计

从最常见到的vec![]到substrait中各种宏来帮助用户完成pallet基本功能

#[pallet::storage]
pub(super) type Something<T: Config> = StorageValue<_, _>;

Rust中的宏,最重要的是帮助开发者少写boilerplate代码,快速且心智简单地完成基础设置和基本功能,从而让开发者更专注在业务逻辑上。

Rust中的宏,大致可分为

  • “声明宏”(Declare Macros)
  • “过程宏”(Procedural Macros)

最开始学习rust时,熟悉的两个语句:

  • let mut v = vec![];中的做Vec类型构建的宏,就是 声明宏
  • #[derive(Debug)]Struct MyStruct { ... },自动给MyStruct添加Debug trait实现,这里就是过程宏的一种(derived macro)

如果要编写自己的宏,或者深入看懂其他的宏,就需要学习Rust中的宏,设计和实现,所幸的是,大神[dtolnay](https://github.com/dtolnay)为我们搞了一个学习路径 - proc-macro-workshop认真完成这里的多个任务/关卡,之后你就可以说对于Rust Macro的编写就达到了中等程度

我目前做完了builder和customDebug,如下是我的一些思路和线索,大概的方向对了,剩下的是细节。

  1. rust宏编写,基本上是在跟ST- syntax tree打交道,其被包装程度介于字符和AST之间;当宏内的语句被解析为DeriveInput,你可以去看它的各个成员变量,并顺着跟下去,或者打印出来,你就会发现有一些字符已经被包装为抽象的节点,比如一个Ident结构,但也会看到类似 ->这样的字符(Punct),编写宏,就是要跟这些东西打交道,添加,修改,删除,做出一个新的TokenStream

    从宏观角度看,rust宏处理就是把一个输入的ST,经过添删改等处理,变成一个新的ST,并返回给编译器做后续处理

      input ST ---> procedural macro ---> Ok(new_st) 
                                     |--->Err(compile error)
    
  2. 以derive宏处理为例,有如下的流程:
    rust macro process flow
    在宏处理过程中,有Syn crate,提供parse等相关函数,把Token Stream,转成ST数据类型,如常见的标识符Ident,符号:: Colon2, 等等各种数据结构,

    有Quote crate,再把这些数据类型转换回TokenStream

  3. 宏编写必须掌握的四个crate

    • syn
    • quote
    • proc_macro2
    • proc_macro

    syn和quote在上图中已经看到;

    proc_macro中主要是定义TokenStream结构,出现时间最早,编译器依赖它;

    proc_macro2出现时间晚于proc_macro,proc_macro2提供了更多的结构和功能,syn,quote都与之配合。
    proc_macro2还提供了TokenTree等,这些都会在declare macro中被使用到。
    proc_macro2::TokenStream具有From/Into trait到proc_macro::TokenStream

    一般的开发套路是:

    • 流程中起始传入,和最后输出的TokenStream是proc_macro::TokenStream
    • 中间过程都使用proc_macro2::TokenStream,最后在使用into()转成proc_macro::TokenStream

参考

  1. 过程宏的基本介绍
  2. syn, proc_macro2等中出现的结构定义(比如Ident,Path,PathSegment)是什么,在这里有详细介绍

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions