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"); // Same as above, but using internal [Flag] Display trait let flags = simple.flags(); let flags_str_result: String = flags .map(|f| format!("{}", f)) .collect::<Vec<String>>() .join(" "); let flags_str_sample = "-#0 +#1 -#2 +#3 -#4 +#5 -#6 +#7"; assert_eq!(flags_str_sample, flags_str_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 # | Name | Desription |
---|---|---|
0 | 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. |
1 | Zero flag | Indicates that the result of an arithmetic or logical operation (or, sometimes, a load) was zero. |
2 | Interrupt flag | Indicates whether interrupts are enabled or masked. |
3 | Decimal flag | Indicates that a bit carry was produced between the nibbles as a result of the last arithmetic operation. |
4 | Break flag | It can be examined as a value stored on the stack. |
5 | Unused | Unused |
6 | Overflow flag | Indicates that the signed result of an operation is too large to fit in the register width using two’s complement representation. |
7 | Negative flag | Indicates 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 Interrupt 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);
Re-exports
pub use layouts::*;
Modules
This module contains useful structures that can be used as meaning of bitflag
Macros
Fast defining of useful types
Structs
Accessory struct for convinient type construction
An iterator through value bits
An iterator through non equal flags
Handle flag’s position, state and value
An iterator through Flags
Traits
Main trait for creating bitfield
Converts bit iterator to value
Converts value to bit iterator
Associated bits layout