#binary #serialization #deserialization #serde #format

macro no-std binary_serde_macros

simple binary serialization and deserialization

25 stable releases

1.0.24 Jan 4, 2024
1.0.23 Nov 24, 2023
1.0.22 Oct 26, 2023
1.0.13 Sep 30, 2023
0.1.0 Jun 17, 2023

#7 in #binary-serialization

Download history 152/week @ 2023-10-18 163/week @ 2023-10-25 23/week @ 2023-11-01 11/week @ 2023-11-08 69/week @ 2023-11-15 148/week @ 2023-11-22 105/week @ 2023-11-29 15/week @ 2023-12-06 56/week @ 2023-12-13 71/week @ 2023-12-20 36/week @ 2023-12-27 95/week @ 2024-01-03 15/week @ 2024-01-10 12/week @ 2024-01-17 43/week @ 2024-01-24 72/week @ 2024-01-31

144 downloads per month
Used in 2 crates (via binary_serde)

MIT license

30KB
620 lines

binary_serde

this is a crate which allows serializing and deserializing rust structs into a packed binary format.

the format does exactly what you expect it to do, it just serializes all fields in order, according to their representation in memory, and according to the chosen endianness.

this is very useful for parsing many common binary formats which often just represent fields in a packed binary representation, just like the format used by this crate.

additionally, this crate is very no_std friendly and allows writing highly performant code because it allows for knowing the serialized size of a type as a compile time constant, which means that the type can be serialized into a buffer on the stack whose size is known at compile time, requiring no heap allocations.

please note that this means that dynamically sized types like &[T], Vec<T> and String are not supported.

bitfields

this crate also supports defining bitfields since those seem to be quite common in a lot of binary formats. the bitfield definition allows the user to specify the bit length of each field of the struct. the bitfields are defined using the binary_serde_bitfield attribute. the order of the fields in a bitfield is treated as lsb first. an example of a bitfield can be seen in the example below.

std support

this crate provides a feature flag called std which enables a bunch of std related features:

  • the error types implement std::error::Error
  • adds the binary_serialize_into and the binary_deserialize_from functions to the BinarySerde trait which allow serializing/deserializing to/from data streams (std::io::Read/std::io::Write).
  • adds a bunch of convenience functions and structs which require std support.

Example

a simple example of serializing and deserializing an elf 32 bit relocation entry:

use binary_serde::{binary_serde_bitfield, BinarySerde, Endianness};

#[derive(Debug, BinarySerde, Default, PartialEq, Eq)]
#[repr(u8)]
enum Elf32RelocationType {
    #[default]
    Direct = 1,
    PcRelative = 2,
    GotEntry = 3,
    // ...
}

#[derive(Debug, Default, PartialEq, Eq)]
#[binary_serde_bitfield(order = BitfieldBitOrder::LsbFirst)]
struct Elf32RelocationInfo {
    #[bits(8)]
    ty: Elf32RelocationType,

    #[bits(24)]
    symbol_index: u32,
}

#[derive(Debug, BinarySerde, Default, PartialEq, Eq)]
struct Elf32RelocationWithAddend {
    offset: u32,
    info: Elf32RelocationInfo,
    addend: u32,
}

fn main() {
    let rel = Elf32RelocationWithAddend::default();

    // serialize the relocation to a statically allocated array on the stack
    let bytes = rel.binary_serialize_to_array(Endianness::Little);

    // deserialize the relocation from its bytes to get back the original value
    let reconstructed_rel =
        Elf32RelocationWithAddend::binary_deserialize(bytes.as_ref(), Endianness::Little).unwrap();

    assert_eq!(rel, reconstructed_rel)
}

License: MIT

Dependencies

~350–790KB
~19K SLoC