Module mycelium_bitfield::pack
source · Expand description
Packing spec types.
This module provides a set of types to make packing bit ranges easier. These
utilities can be used in const fn.
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
usize, u128, u64, u32, u16, and u8, as
PackUsize, Pack128, Pack64, Pack32, Pack16, and
Pack8, respectively.
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 const fn.
§Examples
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 c0ffeeThe 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 c0ffeePacking 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...Structs§
- A spec for packing values into selected bit ranges of
u8values. - A spec for packing values into selected bit ranges of
u16values. - A spec for packing values into selected bit ranges of
u32values. - A spec for packing values into selected bit ranges of
u64values. - A spec for packing values into selected bit ranges of
u128values. - A spec for packing values into selected bit ranges of
usizevalues.