-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7774936
commit 4225479
Showing
3 changed files
with
62 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,122 +1,90 @@ | ||
# bin-proto | ||
|
||
[![Crates.io](https://img.shields.io/crates/v/bin-proto.svg)](https://crates.io/crates/bin-proto) | ||
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) | ||
[![crates](https://img.shields.io/crates/v/bin-proto.svg)](https://crates.io/crates/bin-proto) | ||
[![tests](https://github.com/wojciech-graj/bin-proto/actions/workflows/ci.yml/badge.svg)](https://github.com/wojciech-graj/bin-proto/actions/workflows/ci.yml) | ||
[![docs.rs](https://docs.rs/bin-proto/badge.svg)](https://docs.rs/bin-proto) | ||
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) | ||
|
||
[Documentation](https://docs.rs/bin-proto) | ||
Simple and fast bit-level protocol definitions in Rust. | ||
|
||
Simple bit-level protocol definitions in Rust. | ||
|
||
An improved and modernized fork of [protocol](https://crates.io/crates/bin-proto). A more efficient but less feature-rich alternative to [deku](https://crates.io/crates/deku). | ||
An improved and modernized fork of | ||
[protocol](https://crates.io/crates/bin-proto). A more efficient but (slightly) | ||
less feature-rich alternative to [deku](https://crates.io/crates/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](https://docs.rs/bitstream-io/latest/bitstream_io/) if you need bit streams, as their `BitRead` and `BitWrite` traits are being used internally. | ||
implemented on types, allowing structured data to be sent and received from any | ||
binary stream. It is recommended to use | ||
[bitstream_io](https://docs.rs/bitstream-io/latest/bitstream_io/) if you need | ||
bit streams, as their `BitRead` and `BitWrite` traits are being used internally. | ||
|
||
## Usage | ||
## Example | ||
|
||
Add this to your `Cargo.toml`: | ||
|
||
```toml | ||
[dependencies] | ||
bin-proto = { version = "0.1", features = ["derive"] } | ||
bin-proto = "0.1" | ||
``` | ||
|
||
And then define a type with the `#[derive(bin_proto::Protocol)]` attribute. | ||
|
||
## Alternatives | ||
|
||
This crate's main alternative is [deku](https://crates.io/crates/deku). `deku` has more attributes that can be used to customize the co/dec behaviour, but the following is exclusive to `bin-proto`: | ||
- easily pass around arbitrary context | ||
- check that all enum variants fit in bitfield | ||
- co/dec packets to/from a non-byte-aligned stream | ||
- read a stream until it ends, without a length prefix | ||
|
||
### Performance comparison | ||
|
||
`bin-proto` is significantly faster than `deku` in almost all of the benchmarks. The units for the below table are ns/iter. 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` | 18 | 86 | 1,615 | 791 | 103 | 126 | | ||
| `deku` | 32 | 141 | 1,544 | 5,102 | 1,387 | 562 | | ||
|
||
## Example | ||
|
||
```rust | ||
use bin_proto::Protocol; | ||
|
||
#[derive(Debug, Protocol, PartialEq)] | ||
#[protocol(discriminant = "u8")] | ||
#[protocol(discriminant_type = "u8")] | ||
#[protocol(bits = 4)] | ||
enum Version { | ||
enum E { | ||
V1 = 1, | ||
#[protocol(discriminant = "4")] | ||
V4 = 4, | ||
} | ||
|
||
#[derive(Debug, Protocol, PartialEq)] | ||
struct Flags { | ||
struct S { | ||
#[protocol(bits = 1)] | ||
reserved: bool, | ||
#[protocol(bits = 1)] | ||
dont_fragment: bool, | ||
#[protocol(bits = 1)] | ||
more_fragments: bool, | ||
} | ||
|
||
#[derive(Debug, Protocol, PartialEq)] | ||
struct IPv4 { | ||
version: Version, | ||
#[protocol(bits = 4)] | ||
internet_header_length: u8, | ||
#[protocol(bits = 6)] | ||
differentiated_services_code_point: u8, | ||
#[protocol(bits = 2)] | ||
explicit_congestion_notification: u8, | ||
total_length: u16, | ||
identification: u16, | ||
flags: Flags, | ||
#[protocol(bits = 13)] | ||
fragment_offset: u16, | ||
time_to_live: u8, | ||
protocol: u8, | ||
header_checksum: u16, | ||
source_address: [u8; 4], | ||
destination_address: [u8; 4], | ||
bitflag: bool, | ||
#[protocol(bits = 3)] | ||
bitfield: u8, | ||
enum_: E, | ||
#[protocol(write_value = "self.arr.len() as u8")] | ||
arr_len: u8, | ||
#[protocol(length = "arr_len as usize")] | ||
arr: Vec<u8>, | ||
#[protocol(flexible_array_member)] | ||
read_to_end: Vec<u8>, | ||
} | ||
|
||
assert_eq!( | ||
IPv4::from_bytes(&[ | ||
0b0100_0000 // Version: 4 | ||
| 0b0101, // Header Length: 5, | ||
0x00, // Differentiated Services Codepoint: 0, Explicit Congestion Notification: 0 | ||
0x05, 0x94, // Total Length: 1428 | ||
0x83, 0xf6, // Identification: 0x83f6 | ||
0b0100_0000 // Flags: Don't Fragment | ||
| 0b0_0000, 0x00, // Fragment Offset: 0 | ||
0x40, // Time to Live: 64 | ||
0x01, // Protocol: 1 | ||
0xeb, 0x6e, // Header Checksum: 0xeb6e | ||
0x02, 0x01, 0x01, 0x01, // Source Address: 2.1.1.1 | ||
0x02, 0x01, 0x01, 0x02, // Destination Address: 2.1.1.2 | ||
], &bin_proto::Settings::default()).unwrap(), | ||
IPv4 { | ||
version: Version::V4, | ||
internet_header_length: 5, | ||
differentiated_services_code_point: 0, | ||
explicit_congestion_notification: 0, | ||
total_length: 1428, | ||
identification: 0x83f6, | ||
flags: Flags { | ||
reserved: false, | ||
dont_fragment: true, | ||
more_fragments: false, | ||
}, | ||
fragment_offset: 0x0, | ||
time_to_live: 64, | ||
protocol: 1, | ||
header_checksum: 0xeb6e, | ||
source_address: [2, 1, 1, 1], | ||
destination_address: [2, 1, 1, 2], | ||
S::from_bytes(&[ | ||
0b1000_0000 // bitflag: true (1) | ||
| 0b101_0000 // bitfield: 5 (101) | ||
| 0b0001, // enum_: V1 (0001) | ||
0x02, // arr_len: 2 | ||
0x21, 0x37, // arr: [0x21, 0x37] | ||
0x01, 0x02, 0x03, // read_to_end: [0x01, 0x02, 0x03] | ||
], &bin_proto::Settings::default()).unwrap(), | ||
S { | ||
bitflag: true, | ||
bitfield: 5, | ||
enum_: E::V1, | ||
arr_len: 2, | ||
arr: vec![0x21, 0x37], | ||
read_to_end: vec![0x01, 0x02, 0x03], | ||
} | ||
); | ||
``` | ||
|
||
## Performance / Alternatives | ||
|
||
This crate's main alternative is [deku](https://crates.io/crates/deku), and [binrw](https://crates.io/crates/binrw) for byte-level protocols. | ||
|
||
`bin-proto` is significantly faster than `deku` in all of the tested scenarios. | ||
The units for the below table are `ns/iter`, taken from | ||
[github CI](https://github.com/wojciech-graj/bin-proto/actions/runs/8458342566/job/23172355723). | ||
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` | 28 | 100 | 1,374 | 1,679 | 174 | 208 | | ||
| `deku` | 67 | 226 | 2,963 | 9,296 | 2,734 | 1,013 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters