[][src]Crate simple_bitfield

Crate to create simple C-style bitfields with the same memory structure as the underlying data type (typically integer). Can be used in #![no_std] environments.

Properties of such bitfields:

  • they have the exact same memory layout and size as the underlying primitive type;
  • their size is checked at compile-time, so it's not possible to add a field that won't fit into the underlying type;
  • their fields can be accessed by name (my_bitfield.some_field) which aids readability;
  • each field has the same set of functions (get, set, set_checked and more);
  • each field has its own distinct type;
  • it's possible to skip (and not name) any number of bits

The bitfield macro was inspired by https://guiand.xyz/blog-posts/bitfields.html.

Example:

use simple_bitfield::{bitfield, Field};
 
bitfield! {
    // Bitfield with underlying type `u32`
    struct MyBitfield<u32> {
        field1: 3, // First field (least significant) of size 3 bits
        field2: 9,
        _: 6,      // Fields named `_` are skipped (offsets are preserved)
        field3: 1  // Last bit (closest to the highest bit of `u32`)
    }
 
    // Multiple bitfields can be defined within one macro invocation
   struct AnotherBitfield<u8> {
       _: 7,
       highest_bit: 1
   }
}

fn main() {
   // Create bitfield object
   let mut a_bitfield = MyBitfield::new(12345);

   // Get the field's value (of underlying type)
   let field3: u32 = a_bitfield.field3.get();

   println!(
       "{:#b} => {:#b}, {:#b}, {:#b}",
       u32::from(a_bitfield), // Convert bitfield to underlying type
       field3,
       a_bitfield.field2.get(),
       a_bitfield.field1.get()
   );

   // Update just that field
   a_bitfield.field1.set(0);

   println!("{:#b}", u32::from(a_bitfield));

   println!("{}\n{:?}", a_bitfield, a_bitfield);
   // MyBitfield(12344)
   // MyBitfield(field1: 0, field2: 7, field3: 0)

   // The type can be inferred, of course
   let another_one: AnotherBitfield::AnotherBitfield = AnotherBitfield::new(184);
    
   // Fields cannot be moved or copied!
   // let another_one_highest = another_one.highest_bit;

   // Each field has its own type
   let another_one_highest: &AnotherBitfield::highest_bit = &another_one.highest_bit;
   println!("{:#b}", another_one_highest.get())
}

These bitfields are simple

One bitfield is essentially one integer that has fields whose get methods return data of the same integer type. Bitfields that contain more than one integer or any type that doesn't satisfy the Bitfield and Field traits are not yet possible.

Structs that contain multiple bitfields are possible, and their size can be preserved via the #[repr(packed)] attribute. Care must be taken of the field access because code like a_bitfield.field.get() borrows a_bitfield, which can result in unaligned access if the struct with the bitfields is #[repr(packed)].

The TestBitfield module is only present in the documentation and shows how a bitfield is structured internally.

Modules

TestBitfield

This module represents a single bitfield.

Macros

bitfield

Creates bitfield types.

Traits

Bitfield

The trait that's implemented for all bitfields. Used mainly to access the bitfield's underlying type, Self::BaseType.

Field

The trait that's implemented for all fields of all bitfields. Allows the nice my_bitfield.some_field.get() syntax.