【问题标题】:Rust bincode enum binary serialisationRust bincode enum 二进制序列化
【发布时间】:2020-10-24 10:00:34
【问题描述】:

我对 Rust 相当陌生,并且在我的项目中使用 bincode。枚举变体的编码是我在与现有服务器交互时一直试图处理的一个问题。旧项目是用 C 编写的,并定义了“fshort-enums”的编译器选项。

在旧的 C 项目中,我会定义一个类似的枚举:

enum test_enum {
    Start,
    Init,
    Complete,
}

然后当这个数据被放入数据包时,它会占用 1 个字节,如下所示:

0x00,
0x01,
0x02

如果我将枚举定义为:

enum test_enum {
    Start,
    Init,
    Complete = 65535,
}

那么当这个数据被放入数据包时,每个变体都会占用 2 个字节,如下所示:

0x00 0x00,
0x01 0x00,
0x02 0x00

现在我找到了一种方法来配置 bincode 枚举编码,以将默认的 4 字节更改为适合以下值的大小:

#[derive(Serialize, Deserialize)]
enum TestEnum {
    Start,
    Init,
    Complete = 65535,
}

let x = TestEnum::Complete;
if let Ok(bytes) = bincode::options().with_varint_encoding().serialize(&x) {
    println!("{:?}", bytes); // [2]
}

问题1:如何强制bincode让所有变体占用2个字节?

问题2:如何强制bincode 应用枚举变量值? (在本例中,TestEnum::Complete 的值为 2 而不是 65535)。

【问题讨论】:

  • bincode的重点是为你处理这个,你不能配置这些

标签: serialization enums rust bincode


【解决方案1】:

Options::with_varint_encoding 可能不是你想要的,因为它只会对小于 256 的整数使用 1 个字节。你可以使用Options::with_fixint_encoding 对整数进行编码,其精度与它们的 Rust 类型相同,但你不需要'不需要指定它,因为它已经是默认值了。

Serde 是结构化的;它并不真正关心数据在内存中的实际表示方式。您分配给枚举的数值会丢失,bincode 只会看到变体的名称。

您可以通过配置serde 将枚举转换为整数,然后再将其暴露给bincode 序列化程序来解决此问题:

#[derive(Serialize, Deserialize, Copy, Clone)]
#[serde(into = "u16")]
enum TestEnum {
    Start,
    Init,
    Complete = 65535,
}

impl From<TestEnum> for u16 {
    fn from(value: TestEnum) -> u16 {
        value as u16
    }
}

那么你的代码给出了预期的结果:

let x = TestEnum::Complete;
if let Ok(bytes) = bincode::serialize(&x) {
    println!("{:?}", bytes); // [255, 255]
}

【讨论】:

  • 非常感谢您的帮助。我刚刚尝试过,它完全按照我的需要工作。非常感谢!
【解决方案2】:

我确实使用了@Peter Hall 提供的答案,但我必须为所有已定义的枚举(有很多)添加一个实现,以便能够序列化它们,并且第二个实现能够反序列化.所以我继续我的调查并找到了一个对我来说似乎更有用的替代方案。我现在没有为每个枚举添加一个实现,而是使用 crates.io 中的 num_enum crate 并向枚举添加一些属性。所以代码如下所示:

use num_enum::{IntoPrimitive, TryFromPrimitive};

#[derive(Serialize, Deserialize, Copy, Clone)]
#[serde(into = "u16", try_from = "u16")]
#[repr(u16)]
enum TestEnum {
    Start,
    Init,
    Complete = 65535,
}

我只是认为这可能会在将来对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 2014-01-04
    • 2016-07-27
    • 1970-01-01
    • 2012-09-12
    • 2017-10-18
    • 1970-01-01
    • 2021-12-03
    • 2011-03-02
    • 2010-12-17
    相关资源
    最近更新 更多