如何在Rust的宏系统中评估表达式?

5

我正在尝试通过编写一个简单的宏来学习Rust宏系统,该宏基于一些无符号整数类型(u8u16u32u64)生成一个结构体。我想要像这样的东西:

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

更具体地说,我正在寻找一种方法在无符号整数类型中以不同的偏移量存储特定信息。其中一个用例是读取某些字节并构建某种“消息”:
[ 15 14 13 12 11 10 09 08 | 07 06 05 04 03 02 01 01 ]

这条信息的上半部分包含一些数据/信息,下半部分是版本字段。(这只是一个玩具示例)。

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

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

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

我知道bitflagsbitfield。但它们都不符合我的用例。

1个回答

5

声明式宏 (macro_rules)

在声明式宏中无法评估表达式。声明式宏仅能创建、删除或移动输入代码抽象语法树 (AST) 的部分内容。在宏扩展期间不会发生任何评估(甚至名称“扩展”就是一个提示)。

你所能做的最好办法是创建可在编译时评估的代码,这要在宏展开之后进行。在编译时有效的代码子集是有限的,但它将来会增长。

过程式宏

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

然而,没有能力重用 Rust 代码的正常评估方式。你将不得不接受文字值并自己进行所有计算。

你的特定示例

不清楚你希望宏的结果是什么。请记住,宏没有“创造”新的 Rust 概念的能力,它们只允许你用更少的字符表达现有的重复概念。

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

另请参见:


我明白了。我越想越觉得使用宏来反序列化二进制消息是错误的方法。感谢您的澄清。 - user8725011

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接