gpt4 book ai didi

rust - Rust 中的编译时数据包构造

转载 作者:行者123 更新时间:2023-11-29 08:00:10 26 4
gpt4 key购买 nike

我有一个 C++ 程序,我在其中使用模板元编程来生成要“通过网络”发送的小型二进制格式数据包,这比分配固定大小缓冲区的更简单的方法提供了更好的安全性和清晰度,并且使用手动计算的偏移量将各种数据项复制到其中。

int foo(int fd, long long data1, float f1)
{
auto m = membuf()
.append<char>(0xAA).append<char>(0xBB) // header
.append(data1)
.append(f1)
.append(555); // in the pipe (arbitary extra data)
return write(fd, m.data(), m.size());
}

这将发送一个由两个字节 0xAA0xBB 组成的数据包,(例如)来自 data1 的 8 个字节,来自 data1 的 4 个字节f1,和4个字节组成555。 (int 等的实际大小当然取决于编译器/架构细节,但我也可以使用例如 uint64_t 类型来进行精确控制)。

(注意:membuf 的完整实现与问题并不相关,但如果有兴趣,您可以在这里查看:https://godbolt.org/z/sr0Cuu)

这种情况下的重要特征是:

  • 不涉及堆分配,并且
  • 数据包的大小和每个值的偏移量是在编译时计算的
  • 都是标准的 C++,没有扩展,没有实验性的特性(实际上是 C++11)

碰巧,这被编译成一个非常有效的指令序列,它简单地在堆栈上分配缓冲区并将每个值写入其中的正确位置:

foo(int, long long, float):
subq $40, %rsp
movl $-17494, %eax
movl $18, %edx
movq %rsi, 2(%rsp)
movq %rsp, %rsi
movw %ax, (%rsp)
movl $555, 14(%rsp)
movd %xmm0, 10(%rsp)
call write
addq $40, %rsp
ret

我正在寻找的是一个 Rust 解决方案来实现同样的事情。如果 Rust 编译器目前不能生成与上述一样高效的代码,我并不介意,但满足上述要求很重要:没有堆分配,没有数据包大小或数据偏移的动态计算,没有使用实验性/“不稳定”的语言功能。

我一直在阅读 the Rust book并试图了解我是否以及如何在 Rust 中做到这一点,但到目前为止我一无所获:

  • 泛型似乎没有帮助,因为它们更像是这个词原本意义上的"template",而不是 C++ 意义上的"template"。他们似乎也不允许除类型之外的任何参数化。
  • 宏似乎是 Rust 中选择的元编程工具,但除非我没有正确理解它们在 token 流上运行,而且除非我遗漏了一种方法,否则它们不能做那种事情membuf 示例。

本质上:我想要一个通用类型,由缓冲区大小参数化,它可以接受一个值并返回一个更大的、固定大小的缓冲区,并在末尾附加数据。但也许该规范过于以 C++ 为中心,并且在 Rust 中可以采取另一种策略 - 我只需要弄清楚它是什么!

最佳答案

用实际代码稍微放大我的评论:restruct -crate 可以做你要求的;但是,它确实需要 nightly 截至目前,因为打包和解包是 const 函数,目前还不稳定。

给定您的示例,在将 restructrestruct_derive 添加到依赖项之后:

#![feature(const_int_conversion)]
#![feature(const_fn)]
#![feature(const_slice_len)]
#![feature(const_transmute)]


/// A packer/unpacker for two unsigned bytes, a group of eight unsigned bytes, a group of
/// four unsigned bytes and four padding bytes; all in little endian.
#[derive(restruct_derive::Struct)]
#[fmt="< 2B 8s 4s 4x"]
struct Foo;


fn main() {
let data = (0xAA, 0xBB, [1,2,3,4,5,6,7,8], [4,3,2,1]);

println!("The buffer has a size of {}", Foo::SIZE);

let buf: [u8; Foo::SIZE] = Foo::pack(data);
println!("Packed as {:?}", buf);

let unpacked: <Foo as restruct::Struct>::Unpacked = Foo::unpack(buf);
println!("Unpacked as {:?}", unpacked);
}

关于rust - Rust 中的编译时数据包构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57269765/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com