Crates.io | rustwire |
lib.rs | rustwire |
version | 0.2.0 |
source | src |
created_at | 2024-05-14 16:55:31.847833 |
updated_at | 2024-05-17 19:56:40.70939 |
description | A Rust library for efficient manipulation of encoded protocol buffer messages. |
homepage | |
repository | https://github.com/Basis-Health/rustwire |
max_upload_size | |
id | 1239847 |
size | 64,777 |
A Rust library designed for decoding and manipulating Protobuf-encoded messages.
This is a dependecy-free helper crate and is not meant to be a full-fledged Protobuf library. It is designed to be used in conjunction with a full Protobuf library like prost
or protobuf
. The main use case for us for example is to extract nested Protobuf and replace them with just the id of said nested Protobuf.
A full Protobuf library: Rustwire is not designed to be a full Protobuf library. It is designed to be used in conjunction with a full Protobuf library like prost
or protobuf
.
A protobuf comoformant changeset utility: The main use case of Rustwire is to replace nested Protobuf messages. Rustwire won't check if the changes you make to the message are valid, it will just replace the field with the new field.
Rustwire is made up of three main components:
Extractor: The extractor is used to extract fields from a Protobuf-encoded message.
Replacer: The replacer is used to replace fields in a Protobuf-encoded message.
Encoder: The encoder is used to encode a field into a Protobuf-encoded message. This exists mostly for varint fields.
This library is designed to manipulate encoded messages, as fast as possible thus without decoding. To understand the impact of this, we created three benchmarks (all benchmarks read one field from a message):
Benchmark | Rustwire | Prost |
---|---|---|
11 bytes | 62 ns | 83 ns |
75 bytes | 207 ns | 240 ns |
4k bytes | 63 ns | 488 ns |
This performance comes mostly from the fact that Rustwire does not decode unintresting fields, while Prost does. This means that Rustwire is faster when you only need to read a few fields from a message.
For this benchmark we assume that we have a message called ThisMessage
with the following structure:
message ThisMessage {
int32 field1 = 1;
string field2 = 2;
uint64 field3 = 3;
bool field4 = 4;
User user = 5;
}
The User
message has the following structure:
message User {
string name = 1;
int32 id = 2;
string email = 3;
}
Let's assume that we have many ThisMessage
messages but only few User
's. Protobuf is a binary format, and can easily be used to store data in a database. To optimize the storage size, we want to replace the User
message with just the id
field. To do this in Prost, you would have to:
id
field instead of the User
message.message OutMessage {
int32 field1 = 1;
string field2 = 2;
uint64 field3 = 3;
bool field4 = 4;
int32 user_id = 5;
}
ThisMessage
message, then extract the User
message and replace it with the id
field.For our benchmark this took 532 ns.
In Rustwire, you can
User
message from the ThisMessage
message.let user_field = extract_field_by_tag(encoded_message, 5).unwrap();
let id = extract_field_by_tag(&user_field, 2).unwrap();
id
field.let header = create_header(5, Variant::Varint.into(), &id);
let replace_with = [header, id].concat();
User
message with the id
field.let result = replace_field_with(&mut encoded_message.to_vec(), 5, &replace_with).unwrap();
This took 31 ns.
This project is licensed under the MIT License - see the LICENSE file for details.