3 个不稳定版本
0.2.0 | 2024年5月17日 |
---|---|
0.1.0 | 2024年5月14日 |
#1326 in 编码
51KB
885 行
Rustwire
一个专门用于解码和操作Protobuf编码消息的Rust库。
这是一个无依赖的辅助包,并不打算成为一个完整的Protobuf库。它旨在与像prost
或protobuf
这样的完整Protobuf库一起使用。例如,我们使用它的主要用例是从嵌套的Protobuf中提取内容,并用该嵌套Protobuf的ID替换它们。
什么是Rustwire?
- 快速:Rustwire设计得尽可能快,因为它不会解码整个消息。
- 轻量级:Rustwire是一个没有依赖项的小型库。
Rustwire不是什么?
-
完整的Protobuf库:Rustwire不是设计为完整的Protobuf库。它旨在与像
prost
或protobuf
这样的完整Protobuf库一起使用。 -
protobuf兼容性变更集工具:Rustwire的主要用例是替换嵌套的Protobuf消息。Rustwire不会检查你对该消息所做的更改是否有效,它只是用新字段替换字段。
组件
Rustwire由三个主要组件组成
- 提取器:提取器用于从Protobuf编码的消息中提取字段。
- 替换器:替换器用于替换Protobuf编码的消息中的字段。
- 编码器:编码器用于将字段编码到Protobuf编码的消息中。这主要用于varint字段。
速度
这个库被设计为尽可能快地操作编码的消息,因此无需解码。为了理解这种影响,我们创建了三个基准测试(所有基准测试都是从一个消息中读取一个字段)
读取
基准测试 | Rustwire | Prost |
---|---|---|
11字节 | 62纳秒 | 83纳秒 |
75字节 | 207纳秒 | 240纳秒 |
4k字节 | 63纳秒 | 488纳秒 |
这种性能主要来自于Rustwire不会解码不感兴趣的字段,而Prost会。这意味着当您只需要从消息中读取几个字段时,Rustwire会更快。
写入
在这个基准测试中,我们假设我们有一个名为ThisMessage
的消息,其结构如下
message ThisMessage {
int32 field1 = 1;
string field2 = 2;
uint64 field3 = 3;
bool field4 = 4;
User user = 5;
}
用户消息具有以下结构:
message User {
string name = 1;
int32 id = 2;
string email = 3;
}
假设我们有很多ThisMessage
消息,但只有很少的User
消息。Protobuf是一种二进制格式,可以很容易地用于在数据库中存储数据。为了优化存储空间,我们希望用仅包含id
字段的User
消息来替换User
消息。要在Prost中做到这一点,您需要:
- 创建一个只包含
id
字段的新消息,而不是User
消息。
编码后的消息(点击展开)
message OutMessage {
int32 field1 = 1;
string field2 = 2;
uint64 field3 = 3;
bool field4 = 4;
int32 user_id = 5;
}
- 解码
ThisMessage
消息,然后提取User
消息并将其替换为id
字段。 - 重新编码新消息。
在我们的基准测试中,这花费了532 ns。
在Rustwire中,您可以:
- 从
ThisMessage
消息中提取User
消息。
let user_field = extract_field_by_tag(encoded_message, 5).unwrap();
let id = extract_field_by_tag(&user_field, 2).unwrap();
- 创建一个只包含
id
字段的新消息。
let header = create_header(5, Variant::Varint.into(), &id);
let replace_with = [header, id].concat();
- 用
id
字段替换User
消息。
let result = replace_field_with(&mut encoded_message.to_vec(), 5, &replace_with).unwrap();
这花费了31 ns。
许可证
本项目采用MIT许可证 - 详细内容请参阅LICENSE文件。