Skip to main content

Module io

Module io 

Source
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:

SourceBackingCan seek?Use for
BitReader&[u8] sliceyes (free cursor math)in-memory bytes
StreamBitReaderany Readno (forward only)a stream you read once
BufSourceany Readyes (within a bounded buffer)a socket that also needs to seek
SeekReaderRead + Seekyes (via io::Seek)a large file / container
BytesReader (bytes feature)owned Bytesyeszero-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.