Expand description
The I/O ladder — where the codec reads from and writes to.
The everyday entry points (decode/peek/decode_exact/to_bytes) work on byte
slices and Vecs. When you need to read from a socket or a file, decode_from
takes any Source and encode_into any Sink.
Pick the source by what your input can do:
| Source | Backing | Can seek? | Use for |
|---|---|---|---|
BitReader | &[u8] slice | yes (free cursor math) | in-memory bytes |
StreamBitReader | any Read | no (forward only) | a stream you read once |
BufSource | any Read | yes (within a bounded buffer) | a socket that also needs to seek |
SeekReader | Read + Seek | yes (via io::Seek) | a large file / container |
BytesReader (bytes feature) | owned Bytes | yes | zero-copy async framing |
Seeking is only needed by messages that use #[br(restore_position)]; everything
else runs over the forward-only StreamBitReader too.
§The low-level cursor
BitReader/BitWriter are the bit cursors
under everything — read or write any Bits value at the current bit
offset:
use bnb::{BitReader, BitWriter, u4, u12};
let mut w = BitWriter::new();
w.write(u4::new(0xA)).unwrap();
w.write(u12::new(0xBCD)).unwrap();
assert_eq!(w.into_bytes(), [0xAB, 0xCD]);
let mut r = BitReader::new(&[0xAB, 0xCD]);
assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
assert_eq!(r.read::<u12>().unwrap(), u12::new(0xBCD));§decode_from over each source
The same message decodes from a slice cursor, a forward stream, a buffered socket, or a seekable file — only the source type changes:
use bnb::{bin, BitReader, StreamBitReader, BufSource, SeekReader};
use std::io::Cursor;
#[bin(big)]
#[derive(Debug, PartialEq)]
struct Word { value: u32 }
let bytes = [0x12, 0x34, 0x56, 0x78];
// in-memory slice cursor
let mut r = BitReader::new(&bytes);
assert_eq!(Word::decode_from(&mut r).unwrap(), Word { value: 0x1234_5678 });
// a forward-only `Read` (a `&[u8]` is `Read` but not `Seek`)
let mut s = StreamBitReader::new(&bytes[..]);
assert_eq!(Word::decode_from(&mut s).unwrap(), Word { value: 0x1234_5678 });
// a `Read` with a bounded retain-and-seek buffer (the socket case)
let mut b = BufSource::new(&bytes[..]);
assert_eq!(Word::decode_from(&mut b).unwrap(), Word { value: 0x1234_5678 });
// a `Read + Seek` (a file; here a Cursor over a Vec)
let mut f = SeekReader::new(Cursor::new(bytes.to_vec()));
assert_eq!(Word::decode_from(&mut f).unwrap(), Word { value: 0x1234_5678 });§Encoding
to_bytes() is the common case; encode(&mut impl Write) goes straight to a
socket or file, and encode_into(&mut impl Sink) targets an explicit bit sink.
use bnb::bin;
use bnb::EncodeExt; // brings `.encode(&mut impl Write)` into scope (the `std` feature)
let w = Word { value: 0x1234_5678 };
assert_eq!(w.to_bytes().unwrap(), [0x12, 0x34, 0x56, 0x78]);
let mut out: Vec<u8> = Vec::new(); // any std::io::Write
w.encode(&mut out).unwrap();
assert_eq!(out, [0x12, 0x34, 0x56, 0x78]);§The bytes feature
With --features bytes, BytesReader/BytesWriter decode from / encode to the
bytes crate’s Bytes/BytesMut for zero-copy async framing:
// requires `bnb = { features = ["bytes"] }`
use bnb::{BytesReader, BytesWriter, Sink};
let mut w = BytesWriter::new();
w.write(0x1234u16).unwrap();
let frame = w.freeze(); // a zero-copy `bytes::Bytes`
let mut r = BytesReader::new(frame); // owns the frame, no copy§Bridging to std::io
The ladder above adapts a std::io::Read into a Source
(BufSource/SeekReader). The reverse —
handing a bnb cursor to std::io-based code from a parse_with/write_with — is
Source::as_read and Sink::as_write,
byte views over the cursor. With From<io::Error>, std::io results ? straight
into a BitError:
use bnb::{BitError, BitReader, Source};
use std::io::Read;
fn read_three<S: Source>(r: &mut S) -> Result<[u8; 3], BitError> {
let mut buf = [0u8; 3];
r.as_read().read_exact(&mut buf)?; // a `std::io::Read` view over the cursor
Ok(buf)
}
let mut r = BitReader::new(&[0xAA, 0xBB, 0xCC]);
assert_eq!(read_three(&mut r).unwrap(), [0xAA, 0xBB, 0xCC]);§Streaming and partial input
A StreamBitReader or BufSource
that runs out mid-message reports ErrorKind::Incomplete, the
“read more bytes and retry” signal — distinct from a definitive parse failure. See
errors.