Crate bitfield_layout[][src]

Expand description

This crate is yet another bitfield handling implementation.

The main goal of this crate - provide binding for various data to every bit (flag) within bitfield layout. In many cases bitfield data are read-only and every bit (flag) has some meaning. Then you getting bitfield data it’s useful to get meaning and/or description of setted flags.

This crate provides basic trait BitFieldLayout that provides convenient methods for getting flags and it meanings of user defined structs or enums. Also there is module layouts with accessory structs and macros.

Example: simple string

Bits layout within bitfield may be associated with it meaning in many ways. The simple case - each bit (flag) has simple string description.

use std::{array, fmt, slice};
use either::Either;
use bitfield_layout::{Layout, BitFieldLayout};
 
// New struct that holds bitfield value
struct Simple(u8);
// Associated bit layout implementation
impl Layout for Simple {
    type Layout = slice::Iter<'static, &'static str>;
    fn layout() -> Self::Layout {
        [
            "First flag", 
            "Second flag", 
            "Third flag", 
            "Fourth flag", 
            "Fifth flag", 
            "Sixth flag", 
            "Seventh flag", 
            "Eighth flag", 
        ].iter()
    }
}
// Main trait implementation
impl BitFieldLayout for Simple {
    type Value = u8;
    fn get(&self) -> Self::Value { self.0 }
    fn set(&mut self, new: Self::Value) { self.0 = new; }
}
 
// Now we can use methods provided by trait
 
// Show full data layout (just show flag meanings that we defined)
let layout = Simple::layout();

let layout_result = layout
    .cloned()
    .collect::<Vec<_>>();
let layout_sample = vec![
    "First flag",
    "Second flag",
    "Third flag",
    "Fourth flag",
    "Fifth flag",
    "Sixth flag",
    "Seventh flag",
    "Eighth flag",
];
assert_eq!(layout_sample, layout_result, "Layout");
 
// Assign value to aur bitfield type
let simple = Simple(0b10101010);
// Show every bit (flag) state
let bits = simple.bits();

let bits_result = bits
    .enumerate()
    .map(|(n, b)| format!("Bit #{}: {}", n, if b { "Is set" } else { "Not set" }))
    .collect::<Vec<_>>();
let bits_sample = vec![
    "Bit #0: Not set",
    "Bit #1: Is set",
    "Bit #2: Not set",
    "Bit #3: Is set",
    "Bit #4: Not set",
    "Bit #5: Is set",
    "Bit #6: Not set",
    "Bit #7: Is set",
];
assert_eq!(bits_sample, bits_result, "Bits");
 
// Show bit (flag) state and it meaning
let flags = simple.flags();

let flags_result = flags
    .map(|f| format!("`{}` is {}", f.value, f.is_set))
    .collect::<Vec<_>>();
let flags_sample = vec![
    "`First flag` is false",
    "`Second flag` is true",
    "`Third flag` is false",
    "`Fourth flag` is true",
    "`Fifth flag` is false",
    "`Sixth flag` is true",
    "`Seventh flag` is false",
    "`Eighth flag` is true",
];
assert_eq!(flags_sample, flags_result, "Flags");
 
// Show difference between two bitfield values
let other = Simple(0b11001100);
let diff = simple.diff(other);

let diff_result = diff
    .collect::<Vec<_>>();
let diff_sample = vec![
    Either::Left((1, &"Second flag")),
    Either::Right((2, &"Third flag")),
    Either::Left((5, &"Sixth flag")),
    Either::Right((6, &"Seventh flag")),
];
assert_eq!(diff_sample, diff_result, "Diff");

Example: status register of MOS Technology 6502

One eight-bit field holds seven pieces of information:

Bit #NameDesription
0Carry flagEnables numbers larger than a single word to be added/subtracted by carrying a binary digit from a less significant word to the least significant bit of a more significant word as needed.
1Zero flagIndicates that the result of an arithmetic or logical operation (or, sometimes, a load) was zero.
2Interrupt flagIndicates whether interrupts are enabled or masked.
3Decimal flagIndicates that a bit carry was produced between the nibbles as a result of the last arithmetic operation.
4Break flagIt can be examined as a value stored on the stack.
5UnusedUnused
6Overflow flagIndicates that the signed result of an operation is too large to fit in the register width using two’s complement representation.
7Negative flagIndicates that the result of a mathematical operation is negative.

We can handle this register like:

use std::{array, fmt, slice};
use bitfield_layout::{Layout, BitFieldLayout};
 
// Struct for handle flag name and flag description
struct NameAndDescription<'a>(&'a str, &'a str);
// Implement Display: Name for basic form "{}" and Description for alternative "{:#}"
impl<'a> fmt::Display for NameAndDescription<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = if f.alternate() { self.1 } else { self.0 };
        write!(f, "{}", s)
    }
}
 
// New struct that holds bitfield value
struct StatusRegister(u8);
// Associate bitfield layout with bitfield type
impl StatusRegister {
    const LAYOUT: [NameAndDescription<'static>; 8] = [
        NameAndDescription(
            "Carry flag",
            "Enables numbers larger than a single word to be added/subtracted by \
            carrying a binary digit from a less significant word to the least \
            significant bit of a more significant word as needed."
        ),
        NameAndDescription(
            "Zero flag",
            "Indicates that the result of an arithmetic or logical operation \
            (or, sometimes, a load) was zero."
        ),
        NameAndDescription(
            "Interrupt flag",
            "Indicates whether interrupts are enabled or masked."
        ),
        NameAndDescription(
            "Decimal flag",
            "Indicates that a bit carry was produced between the nibbles as a \
            result of the last arithmetic operation."
        ),
        NameAndDescription(
            "Break flag",
            "It can be examined as a value stored on the stack."
        ),
        NameAndDescription("Unused", "Unused"),
        NameAndDescription(
            "Overflow flag",
            "Indicates that the signed result of an operation is too large to \
            fit in the register width using two's complement representation."
        ),
        NameAndDescription(
            "Negative flag",
            "Indicates that the result of a mathematical operation is negative."
        ),
    ];
}
 
// Implement layout iterator
impl Layout for StatusRegister {
    type Layout = slice::Iter<'static, NameAndDescription<'static>>;
    // Take bitfield layout from associated constant
    fn layout() -> Self::Layout {
        StatusRegister::LAYOUT.iter()
    }
}
// Bitfield trait implementation
impl BitFieldLayout for StatusRegister {
    type Value = u8;
    fn get(&self) -> Self::Value { self.0 }
    fn set(&mut self, new: Self::Value) { self.0 = new; }
}
 
// For example our value has setted Carry and Negative flags
let status = StatusRegister(0b10000100);
 
let result = status.flags()
    .filter(|f| f.is_set)
    .map(|f| format!("Name: {}\nDescription: {:#}\n", f.value, f.value))
    .collect::<Vec<_>>()
    .join("\n");
let sample = "\
Name: Interrupt flag
Description: Indicates whether interrupts are enabled or masked.

Name: Negative flag
Description: Indicates that the result of a mathematical operation is negative.
";
assert_eq!(sample, result);

There are more examples in layouts and BitField

Re-exports

pub use layouts::*;

Modules

layouts

This module contains useful structures that can be used as meaning of bitflag

Macros

layout

Fast defining of useful types

Structs

BitField

Accessory struct for convinient type construction

Bits

An iterator through value bits

Diff

An iterator through non equal flags

Flag

Handle flag state and flag meaning

Flags

An iterator through Flags

Traits

BitFieldLayout

Main trait for creating bitfield

FromBits

Converts bit iterator to value

IntoBits

Converts value to bit iterator

Layout

Associated bits layout