Crate packed_struct [] [src]

Bit-level packing and unpacking for Rust

Build Status

Documentation

Introduction

Packing and unpacking bit-level structures is usually a programming tasks that needlessly reinvents the wheel. This library provides a meta-programming aproach, using attributes to document fields and how they should be packed. The resulting trait implementations provide safe packing, unpacking and runtime debugging formatters with per-field documentation generated for each structure.

Features

  • Plain Rust structures, decorated with attributes
  • MSB or LSB integers of user-defined bit widths
  • Primitive enum code generation helper
  • MSB0 or LSB0 bit positioning
  • Documents the field's packing table
  • Runtime packing visualization
  • Nested packed types
  • Arrays of packed structures as fields
  • Reserved fields, their bits are always 0 or 1

Sample usage

Cargo.toml

[dependencies]
packed_struct = "0.2"
packed_struct_codegen = "0.2"

Including the library and the code generator

extern crate packed_struct;
#[macro_use]
extern crate packed_struct_codegen;

Example of a single-byte structure, with a 3 bit integer, primitive enum and a bool field.

extern crate packed_struct;
#[macro_use] extern crate packed_struct_codegen;

use packed_struct::prelude::*;

#[derive(PackedStruct)]
#[packed_struct(bit_numbering="msb0")]
pub struct TestPack {
    #[packed_field(bits="0..=2")]
    tiny_int: Integer<u8, packed_bits::Bits3>,
    #[packed_field(bits="3..=4", ty="enum")]
    mode: SelfTestMode,
    #[packed_field(bits="7")]
    enabled: bool
}

#[derive(PrimitiveEnum_u8, Clone, Copy, Debug, PartialEq)]
pub enum SelfTestMode {
    NormalMode = 0,
    PositiveSignSelfTest = 1,
    NegativeSignSelfTest = 2,
    DebugMode = 3,
}

fn main() {
    let test = TestPack {
        tiny_int: 5.into(),
        mode: SelfTestMode::DebugMode,
        enabled: true
    };

    let packed = test.pack();
    assert_eq!([0b10111001], packed);

    let unpacked = TestPack::unpack(&packed).unwrap();
    assert_eq!(*unpacked.tiny_int, 5);
    assert_eq!(unpacked.mode, SelfTestMode::DebugMode);
    assert_eq!(unpacked.enabled, true);
}

Packing attributes

Syntax

extern crate packed_struct;
#[macro_use] extern crate packed_struct_codegen;

#[derive(PackedStruct)]
#[packed_struct(attr1="val", attr2="val")]
pub struct Structure {
    #[packed_field(attr1="val", attr2="val")]
    field: u8
}

Per-structure attributes

Attribute Values Comment
size_bytes 1 ... n Size of the packed byte stream
bit_numbering msb0 or lsb0 Bit numbering for bit positioning of fields. Required if the bits attribute field is used.
endian msb or lsb Default integer endianness

Per-field attributes

Attribute Values Comment
bits 0, 0..1, ... Position of the field in the packed structure. Three modes are supported: a single bit, the starting bit, or a range of bits. See details below.
bytes 0, 0..1, ... Same as above, multiplied by 8.
size_bits 1, ... Specifies the size of the packed structure. Mandatory for certain types. Specifying a range of bits like bits="0..2" can substite the required usage of size_bits.
size_bytes 1, ... Same as above, multiplied by 8.
element_size_bits 1, ... For packed arrays, specifies the size of a single element of the array. Explicitly stating the size of the entire array can substite the usage of this attribute.
element_size_bytes 1, ... Same as above, multiplied by 8.
ty enum Packing helper for primitive enums.
endian msb or lsb Integer endianness. Applies to u16/i16 and larger types.

Bit and byte positioning

Used for either bits or bytes on fields. The examples are for MSB0 positioning.

Value Comment
0 A single bit or byte
0.., 0: The field starts at bit zero
0..2 Exclusive range, bits zero and one
0:1, 0..=1 Inclusive range, bits zero and one

More examples

Mixed endian integers

extern crate packed_struct;
#[macro_use] extern crate packed_struct_codegen;

use packed_struct::prelude::*;

#[derive(PackedStruct)]
pub struct EndianExample {
    #[packed_field(endian="lsb")]
    int1: u16,
    #[packed_field(endian="msb")]
    int2: i32
}

fn main() {
    let example = EndianExample {
        int1: 0xBBAA,
        int2: 0x11223344
    };

    let packed = example.pack();
    assert_eq!([0xAA, 0xBB, 0x11, 0x22, 0x33, 0x44], packed);
}

24 bit LSB integers

extern crate packed_struct;
#[macro_use] extern crate packed_struct_codegen;

use packed_struct::prelude::*;

#[derive(PackedStruct)]
#[packed_struct(endian="lsb")]
pub struct LsbIntExample {
    int1: Integer<u32, packed_bits::Bits24>,
}

fn main() {
    let example = LsbIntExample {
        int1: 0xCCBBAA.into()
    };

    let packed = example.pack();
    assert_eq!([0xAA, 0xBB, 0xCC], packed);
}

Nested packed types within arrays

extern crate packed_struct;
#[macro_use] extern crate packed_struct_codegen;

use packed_struct::prelude::*;

#[derive(PackedStruct, Default, Debug, PartialEq)]
#[packed_struct(bit_numbering="msb0")]
pub struct TinyFlags {
    _reserved: ReservedZero<packed_bits::Bits4>,
    flag1: bool,
    val1: Integer<u8, packed_bits::Bits2>,
    flag2: bool
}

#[derive(PackedStruct, Debug, PartialEq)]
pub struct Settings {
    #[packed_field(element_size_bits="4")]
    values: [TinyFlags; 4]
}

fn main() {
    let example = Settings {
        values: [
            TinyFlags { flag1: true,  val1: 1.into(), flag2: false, .. TinyFlags::default() },
            TinyFlags { flag1: true,  val1: 2.into(), flag2: true,  .. TinyFlags::default() },
            TinyFlags { flag1: false, val1: 3.into(), flag2: false, .. TinyFlags::default() },
            TinyFlags { flag1: true,  val1: 0.into(), flag2: false, .. TinyFlags::default() },
        ]
    };

    let packed = example.pack();
    let unpacked = Settings::unpack(&packed).unwrap();

    assert_eq!(example, unpacked);
}

Primitive enums with simple discriminants

Supported backing integer types: u8, u16, u32, u64, i8, i16, i32, i64.

Explicit or implicit backing type:

extern crate packed_struct;
#[macro_use] extern crate packed_struct_codegen;

#[derive(PrimitiveEnum, Clone, Copy)]
pub enum ImplicitType {
    VariantMin = 0,
    VariantMax = 255
}
 
#[derive(PrimitiveEnum_i16, Clone, Copy)]
pub enum ExplicitType {
    VariantMin = -32768,
    VariantMax = 32767
}
 

Modules

debug_fmt

Helper structures for runtime packing visualization.

prelude

Re-exports the most useful traits and types. Meant to be glob imported.

types

Implementations and wrappers for various packing types.

Enums

PackingError

Packing errors that might occur during packing or unpacking

Traits

PackedStruct

A structure that can be packed and unpacked from a byte array.

PackedStructInfo

Infos about a particular type that can be packaged.

PackedStructSlice

A structure that can be packed and unpacked from a slice of bytes.

PrimitiveEnum

An enum type that can be packed or unpacked from a simple primitive integer.