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 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...
Structs
- A spec for packing values into selected bit ranges of
u8
values. - A spec for packing values into selected bit ranges of
u16
values. - A spec for packing values into selected bit ranges of
u32
values. - A spec for packing values into selected bit ranges of
u64
values. - A spec for packing values into selected bit ranges of
u128
values. - A spec for packing values into selected bit ranges of
usize
values.