我如何计算 Rust 宏系统中的表达式?

How do I evaluate expressions in Rust's macro system?

我正在尝试通过编写一个简单的宏来学习 Rust 宏系统,该宏基于某种无符号整数类型(u8u16u32u64).我想要这样的东西:

bitmessage! {
    struct Header(u16);
    version: 8, 5; // the first number is the length, second is value
    data: 8, 5;
}

更具体地说,我正在寻找某种方法来将某些信息存储在具有各种偏移量的无符号整数类型中。一个用例是读取一些字节并构造某种 "message":

[ 15 14 13 12 11 10 09 08 | 07 06 05 04 03 02 01 01 ]

消息的上半部分包含一些data/information,下半部分是版本控制字段。 (这只是一个玩具示例)。

到目前为止,这是我的努力,但内部重复扩展无法编译:

macro_rules! bitmessage {
(struct $name:ident($n:ty); 
    $($field_name:ident: $length:expr, $value:expr;)*)  => {
         struct $name ($n);
         $($name.1 = $name.1 | $value << $length)*
    };
}

一个解决方案可能是将相关字节存储在一个结构中,直接(或使用特征)实现它以获得适当的字段,但这会涉及太多的位移逻辑(这没有问题,但是一定有更方便的方法)。

我知道 bitflags and bitfield。它们都不符合我的用例。

声明性宏(macro_rules

您不能计算声明性宏中的表达式。声明性宏仅创建、删除或移动输入代码的抽象语法树 (AST) 的部分内容。宏扩展期间不进行计算(甚至名称 "expansion" 也是一个提示)。

你能做的最好的事情就是创建可以在编译时评估的代码,在宏被扩展之后。在编译时有效的代码子集是有限的,但它会在未来增长。

程序宏

过程宏更复杂但更强大。它们被实现为任意 Rust 代码,它们可以解析任意 Rust 代码,输出更多任意 Rust 代码。

但是,无法重用评估 Rust 代码的正常方法。您将不得不接受文字值并自己进行所有计算。

你的具体例子

不清楚您希望宏的结果是什么。请记住,宏无法 "make up" 新的 Rust 概念,它们只允许您用更少的字符表达现有的重复概念。

正因为如此,我总是建议人们完整地写出前两个重复的案例。这迫使您编写完整有效的 Rust 代码并识别它们之间的差异。然后,您可以使用任何普通的 Rust 技术提取共性。

另请参阅: