Crate binrw

Source
Expand description

binrw helps you write maintainable & easy-to-read declarative binary data readers and writers using ✨macro magic✨.

Adding #[binrw] (or #[derive(BinRead, BinWrite)]) to a struct or enum generates a parser that can read that type from raw data and a serialiser that can write it back:

use binrw::{
    binrw,    // #[binrw] attribute
    BinRead,  // trait for reading
    BinWrite, // trait for writing
};

#[binrw]
#[brw(little)]
struct Point(i16, i16);

// Read a point from bytes
let point = Point::read(&mut Cursor::new(b"\x80\x02\xe0\x01")).unwrap();
assert_eq!(point, Point(640, 480));

// Write the point back to bytes
let mut writer = Cursor::new(Vec::new());
point.write(&mut writer).unwrap();
assert_eq!(writer.into_inner(), b"\x80\x02\xe0\x01");

binrw types are composable and nestable, so everything just works as expected without any special logic or glue code:

#[derive(BinRead)]
#[br(big, magic = b"SHAP")]
enum Shape {
    #[br(magic(0u8))] Rect {
        left: i16, top: i16, right: i16, bottom: i16
    },
    #[br(magic(1u8))] Oval { origin: Point, rx: u8, ry: u8 }
}

let oval = Shape::read(&mut Cursor::new(b"SHAP\x01\x80\x02\xe0\x01\x2a\x15")).unwrap();
assert_eq!(oval, Shape::Oval { origin: Point(640, 480), rx: 42, ry: 21 });

Types that can’t implement binrw traits directly (e.g. types from third party crates) can also be read and written using free parser functions or by mapping values.

Unlike “zero-copy” libraries, the in-memory representation of binrw structs doesn’t need to match the raw data. This can allow for better memory performance, especially on architectures where unaligned memory access is slow. Also, because data is never transmuted, there is no risk of undefined behaviour.

§Input and output

binrw reads data from any object that implements io::Read + io::Seek, and writes data to any object that implements io::Write + io::Seek. (Unseekable streams are also supported, but require a wrapper.) This means that data can come from memory, network, disk, or any other streaming source. It also means that low-level data operations like buffering and compression are efficient and easy to implement.

binrw also includes extension traits for conveniently reading and writing directly on the stream objects:

use binrw::{BinReaderExt, BinWriterExt};

let mut stream = Cursor::new(b"\x00\x0a".to_vec());
let val: u16 = stream.read_be().unwrap();
assert_eq!(val, 0xa);

let val = val + 0x10;
stream.write_be(&val).unwrap();
assert_eq!(stream.into_inner(), b"\x00\x0a\x00\x1a");

§Directives

Handling things like magic numbers, byte ordering, and padding & alignment is typical when working with binary data, so binrw includes a variety of built-in directives for these common cases that can be applied using the #[br], #[bw], and #[brw] attributes:

#[binrw]
#[brw(big, magic = b"DOG", assert(name.len() != 0))]
struct Dog {
    #[bw(try_calc(u8::try_from(bone_piles.len())))]
    bone_pile_count: u8,

    #[br(count = bone_pile_count)]
    bone_piles: Vec<u16>,

    #[br(align_before = 0xA)]
    name: NullString
}

let mut data = Cursor::new(b"DOG\x02\x00\x01\x00\x12\0\0Rudy\0");
let dog = Dog::read(&mut data).unwrap();
assert_eq!(dog.bone_piles, &[0x1, 0x12]);
assert_eq!(dog.name.to_string(), "Rudy")

Directives can also reference earlier fields by name. For tuple types, earlier fields are addressable by self_N, where N is the index of the field.

See the attribute documentation for the full list of available directives.

§Built-in implementations

Implementations for all primitive data types, arrays, tuples, and standard Rust types like Vec are included, along with parsers for other frequently used binary data patterns like null-terminated strings and indirect addressing using offsets. Convenient access into bitfields is possible using crates like modular-bitfield.

See the BinRead and BinWrite traits for the full list of built-in implementations.

§no_std support

binrw supports no_std and includes a compatible subset of io functionality. The alloc crate is required.

Modules§

docs
Additional long-form documentation and reference material.
endian
Type definitions for byte order handling.
error
Functions and type definitions for handling errors.
file_ptr
Type definitions and helpers for handling indirection within a file.
helpers
Helper functions for reading and writing data.
io
Traits, helpers, and type definitions for core I/O functionality.
meta
Traits that expose information about the way types are parsed or serialised.
prelude
The binrw prelude.
punctuated
Type definitions for wrappers which parse interleaved data.

Macros§

args
A convenience macro for constructing named arguments.

Structs§

FilePtr
A wrapper type which represents a layer of indirection within a file.
NullString
A null-terminated 8-bit string.
NullWideString
A null-terminated 16-bit string.
PosValue
A wrapper that stores a value’s position alongside the value.
VecArgs
Named arguments for the BinRead::read_options() implementation of Vec.

Enums§

Endian
Defines the order of bytes in a multi-byte type.
Error
The error type used by BinRead.

Traits§

BinRead
The BinRead trait reads data from streams and converts it into objects.
BinReaderExt
Extension methods for reading BinRead objects directly from a reader.
BinWrite
The BinWrite trait serialises objects and writes them to streams.
BinWriterExt
Extension methods for writing BinWrite objects directly to a writer.
NamedArgs
The NamedArgs trait allows named arguments objects to be constructed using a builder that checks for correctness at compile time.

Type Aliases§

BinResult
A specialized Result type for binrw operations.
FilePtr8
A type alias for FilePtr with 8-bit offsets.
FilePtr16
A type alias for FilePtr with 16-bit offsets.
FilePtr32
A type alias for FilePtr with 32-bit offsets.
FilePtr64
A type alias for FilePtr with 64-bit offsets.
FilePtr128
A type alias for FilePtr with 128-bit offsets.

Attribute Macros§

binread
Attribute macro used to generate an impl of the trait BinRead with support for temporary variables.
binrw
Attribute macro used to generate an impl of both BinRead and BinWrite traits with support for temporary variables.
binwrite
Attribute macro used to generate an impl of the trait BinWrite with support for temporary variables.
parser
Attribute macro used to generate parse_with functions.
writer
Attribute macro used to generate write_with functions.

Derive Macros§

BinRead
Derive macro generating an impl of the trait BinRead.
BinWrite
Derive macro generating an impl of the trait BinWrite.
NamedArgs
Derive macro generating an impl of the trait NamedArgs.