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.
  • Wraps a u8 to add methods for packing bit ranges specified by Pack8.
  • Wraps a u16 to add methods for packing bit ranges specified by Pack16.
  • Wraps a u32 to add methods for packing bit ranges specified by Pack32.
  • Wraps a u64 to add methods for packing bit ranges specified by Pack64.
  • Wraps a u128 to add methods for packing bit ranges specified by Pack128.
  • Wraps a usize to add methods for packing bit ranges specified by PackUsize.
  • A pair of Pack8s, allowing a bit range to be unpacked from one offset in a u8 value, and packed into a different offset in a different value.
  • A pair of Pack16s, allowing a bit range to be unpacked from one offset in a u16 value, and packed into a different offset in a different value.
  • A pair of Pack32s, allowing a bit range to be unpacked from one offset in a u32 value, and packed into a different offset in a different value.
  • A pair of Pack64s, allowing a bit range to be unpacked from one offset in a u64 value, and packed into a different offset in a different value.
  • A pair of Pack128s, allowing a bit range to be unpacked from one offset in a u128 value, and packed into a different offset in a different value.
  • A pair of PackUsizes, allowing a bit range to be unpacked from one offset in a usize value, and packed into a different offset in a different value.