bin-proto

Simple & fast structured bit-level binary co/dec in Rust.
An improved and modernized fork of
protocol. A more efficient but (slightly)
less feature-rich alternative to deku.
This crate adds a trait (and a custom derive for ease-of-use) that can be
implemented on types, allowing structured data to be sent and received from any
binary stream. It is recommended to use
bitstream_io if you need
bit streams, as their BitRead and BitWrite traits are being used internally.
Example
Add this to your Cargo.toml:
[dependencies]
bin-proto = "0.5"
And then define a type with the #[derive(bin_proto::ProtocolRead, bin_proto::ProtocolWrite)] attributes.
use bin_proto::{ProtocolRead, ProtocolWrite, ProtocolNoCtx};
#[derive(Debug, ProtocolRead, ProtocolWrite, PartialEq)]
#[protocol(discriminant_type = "u8")]
#[protocol(bits = 4)]
enum E {
V1 = 1,
#[protocol(discriminant = "4")]
V4,
}
#[derive(Debug, ProtocolRead, ProtocolWrite, PartialEq)]
struct S {
#[protocol(bits = 1)]
bitflag: bool,
#[protocol(bits = 3)]
bitfield: u8,
enum_: E,
#[protocol(write_value = "self.arr.len() as u8")]
arr_len: u8,
#[protocol(tag = "arr_len as usize")]
arr: Vec<u8>,
#[protocol(tag(type = "u16", write_value = "self.prefixed_arr.len() as u16"))]
prefixed_arr: Vec<u8>,
#[protocol(flexible_array_member)]
read_to_end: Vec<u8>,
}
assert_eq!(
S::from_bytes(&[
0b1000_0000 | 0b101_0000 | 0b0001, 0x02, 0x21, 0x37, 0x00, 0x01, 0x33, 0x01, 0x02, 0x03, ], bin_proto::ByteOrder::BigEndian).unwrap(),
S {
bitflag: true,
bitfield: 5,
enum_: E::V1,
arr_len: 2,
arr: vec![0x21, 0x37],
prefixed_arr: vec![0x33],
read_to_end: vec![0x01, 0x02, 0x03],
}
);
You can implement Protocol on your own types, and parse with context:
use bin_proto::{ProtocolRead, ProtocolWrite};
pub struct Ctx;
pub struct NeedsCtx;
impl ProtocolRead<Ctx> for NeedsCtx {
fn read(
_read: &mut dyn bin_proto::BitRead,
_byte_order: bin_proto::ByteOrder,
_ctx: &mut Ctx,
) -> bin_proto::Result<Self> {
Ok(Self)
}
}
impl ProtocolWrite<Ctx> for NeedsCtx {
fn write(
&self,
_write: &mut dyn bin_proto::BitWrite,
_byte_order: bin_proto::ByteOrder,
_ctx: &mut Ctx,
) -> bin_proto::Result<()> {
Ok(())
}
}
#[derive(ProtocolRead, ProtocolWrite)]
#[protocol(ctx = "Ctx")]
pub struct WithCtx(NeedsCtx);
WithCtx(NeedsCtx)
.bytes_ctx(bin_proto::ByteOrder::LittleEndian, &mut Ctx)
.unwrap();
Performance / Alternatives
This crate's main alternative is deku, and binrw for byte-level protocols.
bin-proto is significantly faster than deku in almost most of the tested scenarios.
The units for the below table are ns, taken from
github CI.
You can find the benchmarks in the bench directory.
|
Read enum |
Write enum |
Read Vec |
Write Vec |
Read IPv4 header |
Write IPv4 header |
bin-proto |
29 |
62 |
1,327 |
557 |
173 |
138 |
deku |
1 |
92 |
582 |
937 |
3,234 |
633 |
Roadmap
The following features are planned:
- Bit/byte alignment
no_std support (only after bitstream_io supports it)