【问题标题】:Will changing the ProtoBuffer Varint type from a bool type to an enum type representing all bit-mask values be forward compatible?将 ProtoBuffer Varint 类型从 bool 类型更改为表示所有位掩码值的枚举类型是否可以向前兼容?
【发布时间】:2021-12-08 04:23:56
【问题描述】:

我想让以下 ProtoBuffer 消息向前兼容。

当前 Storage 消息将 state 字段定义为 bool 类型:

message Storage {
    bool state = 1;
}

在 Protobuffer 编码中,它将 Varint 类型如 boolenum 类型编码为以下格式:

|1-bit sequence number|4-bit serial number|3-bit data type|n-bit payload|

对于Varint类型,数据类型值会变成000:

|X|XXXX|000|XXXX...|

由于Storage消息结构只包含一个序列号为1的字段,由于序列号尚未解析到最后一个字节。因此,上述格式将变为:

|0|0001|000|XXXX...|

现在,如果设置 Storage.state = 0,它将按如下方式存储:

|0|0001|000|<0 will not be encoded>

Storage 消息的 Protobuffer 值将变为 0x8。

如果设置Storage.state = 1,则存储如下:

|0|0001|000|00000001|

Storage 消息的 Protobuffer 值将变为 0x8 0x1。

现在,我想将上述 Storage.state 定义从 bool 类型更改为 enum输入如下:

// BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
//-------------------------------------------------------
//  0   |  0   |  0   |  0   |  0   |  0   |  0   |  0   | = STATE0 (0)
//  0   |  0   |  0   |  0   |  0   |  0   |  0   |  1   | = STATE1 (1)
//  0   |  0   |  0   |  0   |  0   |  0   |  1   |  0   | = STATE2 (2)
//  0   |  0   |  0   |  0   |  0   |  0   |  1   |  1   | = STATE2 (3)
//... so go on
//  1   |  1   |  1   |  1   |  1   |  1   |  1   |  0   | = STATE2 (254)
//  1   |  1   |  1   |  1   |  1   |  1   |  1   |  1   | = STATE2 (255)

enum State {
    STATE0 = 0;
    STATE1 = 1;
    STATE2 = 2;
    STATE3 = 3;
    //... so go on
    STATE254 = 254;
    STATE255 = 255;
}

message Storage {
    State state = 1
}

所以现在,在 Protobuf 编码中,

如果设置Storage.state = State.STATE0,则存储如下:

|0|0001|000|<0 will not be encoded>

Storage 消息的 Protobuffer 值将变为 0x8。

如果设置Storage.state = State.STATE1,则存储如下:

|0|0001|000|00000001|

Storage 消息的 Protobuffer 值将变为 0x8 0x1。

如果设置Storage.state = State.STATE2,则存储如下:

|0|0001|000|00000010|

Storage 消息的 Protobuffer 值将变为 0x8 0x2。

如果设置Storage.state = State.STATE255,则存储如下:

|0|0001|000|11111111|

Storage 消息的 Protobuffer 值将变为 0x8 0xFF。

此更改是否仍向前兼容 proto2proto3 以及 C 和 Java?

我的问题基于以下参考: google protocol buffer -- the coding principle of protobuf II

【问题讨论】:

  • 问题:你的状态 - 这 256 个选项都是独立的东西,还是你实际上试图表示按位状态值,即 C# 术语中的 [Flags] enum(是的,我知道你没有问关于 C#)
  • 是的,按位状态值,但专门用于 C 和 Java 实现。

标签: protocol-buffers proto protobuf-java protobuf-c


【解决方案1】:

我假设您实际上要在此处存储的是:按位状态值 - 在 C# 中可能是 [Flags] enum(提及纯粹是为了设置上下文)。

老实说,用每位组合的值声明一个枚举:不是一个好主意;它会迅速升级,而且使用起来不直观。在复制/粘贴大量行时,它还可能出现愚蠢的错误......

// omitted... 212 lines - but would you spot the error?
STATE213 = 213;
STATE214 = 214;
STATE215 = 214;
STATE216 = 216;
STATE217 = 217;
// ... etc

(好的,该特定错误需要允许别名标志,但是:你明白了)


在proto2中,枚举应该被识别;当遇到意外的枚举值时,它会变得有点……朦胧,有以下任何一种:

  1. 解析失败
  2. 被视为未知字段(需要通过单独的 API 访问)
  3. 通过整数值静默处理和解析(具有保留位标志的效果)

由于每个标志组合都没有枚举定义,因此您想要这里是选项 3,但并非在所有实现中都能保证。


在 proto3 中,框架尽可能向 3 的方向倾斜,explicitly in the language specification,存储和检索整数值(具有保留位标志的效果)但是它还明确指出某些平台不允许开放枚举类型 - 例如,Java。


由于这个限制,既然你在标签中提到了,我建议直接使用整数。它至少会在所有实现上类似地工作。与您提出的解决方案相比,它至少可用 - 但通常更多可用;考虑一下它作为枚举是如何工作的:

obj.state = State.State217;

vs 为整数:

obj.state = 217;

这也将允许使用按位组合/测试/等操作重新值,这不是封闭枚举类型的情况。


至于boolenumint32/uint32/sint32(以及64位对应)在技术上是否可以互换(如果规模允许):是;它们都被编码为 varint。

【讨论】:

  • 是的,我更喜欢选项 3,因为我已经有一个嵌入式 ANSI C 结构,它被转换为嵌入式 NanoPB C proto2 有效负载并通过 USB/蓝牙串行接口发送到我的 Android 应用程序,它使用 Java proto2 ProtoBuf 格式。由于 C 结构设计缺乏前瞻性,将状态字段定义为 8 位整数来表示布尔状态。因此,我想将状态字段的 ProtoBuf 定义从 8 位有效负载数据 Varint bool 类型切换为具有所有可能的 8 位位掩码值定义的 Varint 枚举类型。
  • 由于 ProtoBuf 中没有 int8 并且对单个字节使用字节定义是矫枉过正的,这是我唯一的选择。除非您想就此发表意见。
  • @ecle 它将占用与 int32 与 enum 相同的空间,具体而言:如果未设置 MSB,则为 1 个字节,如果已设置,则为 2 个字节;所以:你通过枚举获得了什么?我看不到这给你的任何东西。至于bytes 类型:是的,这里不必要的开销,不要那样做。如果枚举部分是为了验证定义的值(即不允许 3624):那将无法可靠地工作。这不是枚举的用途。
  • @ecle 并且第 N 次:在 int32 和枚举之间的有效负载中实际上没有任何变化;它们被编码相同,所以:就字节而言,你所说的关于枚举的任何内容:同样适用于 int32
  • @ecle 你所说的适用于fixed32,但是:int32 存储为 varint(哦,0xFF 将是 2 个字节,0xFFFF 将是 3 个字节;varint 基本上是“7 bits plus continuation”,所以 0x7F 是 1 个字节的最大值,0x3FFF 是 2 个字节的最大值)
猜你喜欢
  • 1970-01-01
  • 2022-09-27
  • 1970-01-01
  • 2010-12-28
  • 2018-10-18
  • 2016-07-14
  • 2019-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多