4

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

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。它们都不符合我的用例。

4

1 回答 1

3

声明性宏 ( macro_rules)

您不能评估声明性宏中的表达式。声明性宏仅创建、删除或移动输入代码的抽象语法树 (AST) 的一部分。在宏扩展期间不进行评估(即使名称“扩展”也是一个提示)。

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

程序宏

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

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

你的具体例子

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

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

也可以看看:

于 2018-03-30T15:39:27.810 回答