1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//! **bytes_frame** — the `bytes` feature: zero-copy framing with `BytesWriter` / `BytesReader`.
//! Encode a message into a `bytes::Bytes` (the wire frame you'd hand to a socket), then decode
//! straight from an owned `Bytes` with no copy — and cheaply slice/share it (refcounted). This
//! is the foundation the `tokio` `BinCodec` builds on. (A different angle from `framed`, which
//! paired the adapters with `StreamBitReader`.)
//!
//! Run with: `cargo run -p bitsandbytes --example bytes_frame --features bytes`
use bnb::{BitEncode, BytesReader, BytesWriter, bin};
#[bin(big)]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Packet {
id: u32,
#[brw(count_prefix = u16)] // the u16 length prefix — derived, never stored, checked at encode
payload: Vec<u8>,
}
fn main() {
let pkt = Packet {
id: 0xABCD,
payload: b"zero-copy".to_vec(),
};
// Encode into a `bytes::Bytes` frame (what you'd write to a socket).
let mut w = BytesWriter::new();
pkt.bit_encode(&mut w).unwrap();
let frame: bytes::Bytes = w.freeze();
println!("frame: {} bytes {:02x?}", frame.len(), &frame[..]);
// Decode straight from the owned `Bytes` — `BytesReader` takes it, no copy.
let mut r = BytesReader::new(frame.clone());
let back = Packet::decode(&mut r).unwrap();
assert_eq!(back, pkt);
println!("{back:#?}");
// `Bytes` is refcounted, so a slice is a zero-copy view — e.g. split the 4-byte id off.
let header = frame.slice(0..4);
println!("zero-copy header slice: {:02x?}", &header[..]);
assert_eq!(&header[..], &pkt.id.to_be_bytes());
println!("all checks passed");
}