Packing spec types.
This module provides a set of types to make packing bit ranges easier. These
utilities can be used in
The bit packing utilities consist of a type that defines a specification for
a bit range to pack into, and a wrapper type for an unsigned integer
defining methods to pack bit ranges into it. Packing specs are defined for
Note that the bit packing utilities are generic using macros, rather than
using generics and traits, because they are intended to be usable in
const-eval, and trait methods cannot be
Sorry there are no examples on the individual types, I didn’t want to figure out how to write doctests inside the macro :)
Packing into the least-significant n bits:
use mycelium_bitfield::Pack32; const LEAST_SIGNIFICANT_8: Pack32 = Pack32::least_significant(8); // the number we're going to pack bits into. let base = 0xface_0000; // pack 0xed into the least significant 8 bits let val = LEAST_SIGNIFICANT_8.pack(0xed, base); assert_eq!(val, 0xface_00ed);
Packing specs can be defined in relation to each other.
use mycelium_bitfield::Pack64; const LOW: Pack64 = Pack64::least_significant(12); const MID: Pack64 = LOW.next(8); const HIGH: Pack64 = MID.next(4); let base = 0xfeed000000; // note that we don't need to pack the values in order. let val = HIGH.pack(0xC, base); let val = LOW.pack(0xfee, val); let val = MID.pack(0x0f, val); assert_eq!(val, 0xfeedc0ffee); // i want c0ffee
The same example can be written a little bit more neatly using methods:
const LOW: Pack64 = Pack64::least_significant(12); const MID: Pack64 = LOW.next(8); const HIGH: Pack64 = MID.next(4); // Wrap a value to pack it using method calls. let coffee = Pack64::pack_in(0) .pack(0xfee, &LOW) .pack(0xC, &HIGH) .pack(0x0f, &MID) .bits(); assert_eq!(coffee, 0xc0ffee); // i still want c0ffee
Packing specs can be used to extract values from their packed representation:
assert_eq!(LOW.unpack_bits(coffee), 0xfee); assert_eq!(MID.unpack_bits(coffee), 0x0f); assert_eq!(HIGH.unpack_bits(coffee), 0xc);
Any previously set bit patterns in the packed range will be overwritten, but existing values outside of a packing spec’s range are preserved:
// this is not coffee let not_coffee = 0xc0ff0f; let coffee = LOW.pack(0xfee, not_coffee); // now it's coffee assert_eq!(coffee, 0xc0ffee);
We can also define packing specs for arbitrary bit ranges, in addition to defining them in relation to each other.
use mycelium_bitfield::Pack64; // pack a 12-bit value starting at the ninth bit let low = Pack64::from_range(9..=21); // pack another value into the next 12 bits following `LOW`. let mid = low.next(12); // pack a third value starting at bit 33 to the end of the `u64`. let high = Pack64::from_range(33..); let val = Pack64::pack_in(0) .pack(0xc0f, &mid) .pack(0xfee, &low) .pack(0xfeed, &high) .bits(); assert_eq!(val, 0xfeedc0ffee00); // starting to detect a bit of a theme here...