Crates.io | packed_struct |
lib.rs | packed_struct |
version | 0.10.1 |
source | src |
created_at | 2018-01-14 14:39:32.945207 |
updated_at | 2022-11-16 14:12:16.425568 |
description | Binary-level structure packing and unpacking generator |
homepage | http://www.hashmismatch.net/libraries/packed-struct/ |
repository | https://github.com/hashmismatch/packed_struct.rs |
max_upload_size | |
id | 46789 |
size | 83,373 |
Packing and unpacking bit-level structures is usually a programming tasks that needlessly reinvents the wheel. This library provides a meta-programming approach, using attributes to define 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.
std
: use the Rust standard library. Default.alloc
: use the alloc
crate for no_std
+ alloc
scenarios. Requires nightly Rust.use_serde
: add serialization support to the built-in helper types.byte_types_64
, byte_types_256
: enlarge the size of the generated array, byte and bit width types.[dependencies]
packed_struct = "0.10"
// This is only needed for pre Rust 2018
#[macro_use] extern crate packed_struct;
// Prelude import with the common imports
use packed_struct::prelude::*;
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::Bits::<3>>,
#[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() -> Result<(), PackingError> {
let test = TestPack {
tiny_int: 5.into(),
mode: SelfTestMode::DebugMode,
enabled: true
};
// pack into a byte array
let packed: [u8; 1] = test.pack()?;
assert_eq!([0b10111001], packed);
// unpack from a byte array
let unpacked = TestPack::unpack(&packed)?;
assert_eq!(*unpacked.tiny_int, 5);
assert_eq!(unpacked.mode, SelfTestMode::DebugMode);
assert_eq!(unpacked.enabled, true);
// or unpack from a slice
let unpacked = TestPack::unpack_from_slice(&packed[..])?;
Ok(())
}
use packed_struct::prelude::*;
#[derive(PackedStruct)]
#[packed_struct(attr1="val", attr2="val")]
pub struct Structure {
#[packed_field(attr1="val", attr2="val")]
field: u8
}
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
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.
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
use packed_struct::prelude::*;
#[derive(PackedStruct)]
pub struct EndianExample {
#[packed_field(endian="lsb")]
int1: u16,
#[packed_field(endian="msb")]
int2: i32
}
fn main() -> Result<(), PackingError> {
let example = EndianExample {
int1: 0xBBAA,
int2: 0x11223344
};
let packed = example.pack()?;
assert_eq!([0xAA, 0xBB, 0x11, 0x22, 0x33, 0x44], packed);
Ok(())
}
use packed_struct::prelude::*;
#[derive(PackedStruct)]
#[packed_struct(endian="lsb")]
pub struct LsbIntExample {
int1: Integer<u32, packed_bits::Bits::<24>>,
}
fn main() -> Result<(), PackingError> {
let example = LsbIntExample {
int1: 0xCCBBAA.into()
};
let packed = example.pack()?;
assert_eq!([0xAA, 0xBB, 0xCC], packed);
Ok(())
}
use packed_struct::prelude::*;
#[derive(PackedStruct, Debug, PartialEq)]
#[packed_struct(endian="lsb")]
pub struct Duration {
minutes: u8,
seconds: u8,
}
#[derive(PackedStruct, Debug, PartialEq)]
pub struct Record {
#[packed_field(element_size_bytes="2")]
span: Duration,
events: u8,
}
fn main() -> Result<(), PackingError> {
let example = Record {
span: Duration {
minutes: 10,
seconds: 34,
},
events: 3,
};
let packed = example.pack()?;
let unpacked = Record::unpack(&packed)?;
assert_eq!(example, unpacked);
Ok(())
}
use packed_struct::prelude::*;
#[derive(PackedStruct, Default, Debug, PartialEq)]
#[packed_struct(bit_numbering="msb0")]
pub struct TinyFlags {
_reserved: ReservedZero<packed_bits::Bits::<4>>,
flag1: bool,
val1: Integer<u8, packed_bits::Bits::<2>>,
flag2: bool
}
#[derive(PackedStruct, Debug, PartialEq)]
pub struct Settings {
#[packed_field(element_size_bits="4")]
values: [TinyFlags; 4]
}
fn main() -> Result<(), PackingError> {
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)?;
assert_eq!(example, unpacked);
Ok(())
}
Supported backing integer types: u8
, u16
, u32
, u64
, i8
, i16
, i32
, i64
.
Explicit or implicit backing type:
use packed_struct::prelude::*;
#[derive(PrimitiveEnum, Clone, Copy, PartialEq, Debug)]
pub enum ImplicitType {
VariantMin = 0,
VariantMax = 255
}
#[derive(PrimitiveEnum_i16, Clone, Copy)]
pub enum ExplicitType {
VariantMin = -32768,
VariantMax = 32767
}
fn main() {
use packed_struct::PrimitiveEnum;
let t = ImplicitType::VariantMin;
let tn: u8 = t.to_primitive();
assert_eq!(0, tn);
let t = ImplicitType::from_primitive(255).unwrap();
assert_eq!(ImplicitType::VariantMax, t);
}
use packed_struct::prelude::*;
#[derive(PrimitiveEnum_u8, Debug, Clone, Copy)]
pub enum Field {
A = 1,
B = 2,
C = 3
}
#[derive(PackedStruct, Debug, PartialEq)]
#[packed_struct(bit_numbering="msb0")]
pub struct Register {
#[packed_field(bits="0..4", ty="enum")]
field: EnumCatchAll<Field>
}
License: MIT OR Apache-2.0