#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BitIndex {
Bit0,
Bit1,
Bit2,
Bit3,
Bit4,
Bit5,
Bit6,
Bit7,
}
impl BitIndex {
pub const LSB: BitIndex = BitIndex::Bit0;
pub const fn all() -> &'static [BitIndex] {
&[
BitIndex::Bit0,
BitIndex::Bit1,
BitIndex::Bit2,
BitIndex::Bit3,
BitIndex::Bit4,
BitIndex::Bit5,
BitIndex::Bit6,
BitIndex::Bit7,
]
}
pub const fn position(self) -> u8 {
match self {
BitIndex::Bit0 => 0,
BitIndex::Bit1 => 1,
BitIndex::Bit2 => 2,
BitIndex::Bit3 => 3,
BitIndex::Bit4 => 4,
BitIndex::Bit5 => 5,
BitIndex::Bit6 => 6,
BitIndex::Bit7 => 7,
}
}
}
impl From<BitIndex> for u8 {
fn from(bit_index: BitIndex) -> Self {
bit_index.position()
}
}
impl TryFrom<u8> for BitIndex {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(BitIndex::Bit0),
1 => Ok(BitIndex::Bit1),
2 => Ok(BitIndex::Bit2),
3 => Ok(BitIndex::Bit3),
4 => Ok(BitIndex::Bit4),
5 => Ok(BitIndex::Bit5),
6 => Ok(BitIndex::Bit6),
7 => Ok(BitIndex::Bit7),
_ => Err("Bit index must be in range 0-7"),
}
}
}
impl std::fmt::Display for BitIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bit_index_position() {
assert_eq!(BitIndex::Bit0.position(), 0);
assert_eq!(BitIndex::Bit1.position(), 1);
assert_eq!(BitIndex::Bit2.position(), 2);
assert_eq!(BitIndex::Bit3.position(), 3);
assert_eq!(BitIndex::Bit4.position(), 4);
assert_eq!(BitIndex::Bit5.position(), 5);
assert_eq!(BitIndex::Bit6.position(), 6);
assert_eq!(BitIndex::Bit7.position(), 7);
}
#[test]
fn test_lsb_alias() {
assert_eq!(BitIndex::LSB, BitIndex::Bit0);
assert_eq!(BitIndex::LSB.position(), 0);
assert_eq!(u8::from(BitIndex::LSB), 0);
}
#[test]
fn test_from_bit_index_to_u8() {
assert_eq!(u8::from(BitIndex::Bit0), 0);
assert_eq!(u8::from(BitIndex::Bit1), 1);
assert_eq!(u8::from(BitIndex::Bit2), 2);
assert_eq!(u8::from(BitIndex::Bit3), 3);
assert_eq!(u8::from(BitIndex::Bit4), 4);
assert_eq!(u8::from(BitIndex::Bit5), 5);
assert_eq!(u8::from(BitIndex::Bit6), 6);
assert_eq!(u8::from(BitIndex::Bit7), 7);
assert_eq!(u8::from(BitIndex::LSB), 0);
}
#[test]
fn test_try_from_u8_to_bit_index() {
assert_eq!(BitIndex::try_from(0u8), Ok(BitIndex::Bit0));
assert_eq!(BitIndex::try_from(1u8), Ok(BitIndex::Bit1));
assert_eq!(BitIndex::try_from(2u8), Ok(BitIndex::Bit2));
assert_eq!(BitIndex::try_from(3u8), Ok(BitIndex::Bit3));
assert_eq!(BitIndex::try_from(4u8), Ok(BitIndex::Bit4));
assert_eq!(BitIndex::try_from(5u8), Ok(BitIndex::Bit5));
assert_eq!(BitIndex::try_from(6u8), Ok(BitIndex::Bit6));
assert_eq!(BitIndex::try_from(7u8), Ok(BitIndex::Bit7));
assert!(BitIndex::try_from(8u8).is_err());
assert!(BitIndex::try_from(255u8).is_err());
}
#[test]
fn test_all_bit_indices() {
let all = BitIndex::all();
assert_eq!(all.len(), 8);
assert_eq!(all[0], BitIndex::Bit0);
assert_eq!(all[7], BitIndex::Bit7);
for (i, &bit_index) in all.iter().enumerate() {
assert_eq!(bit_index.position(), i as u8);
}
}
#[test]
fn test_display() {
assert_eq!(format!("{}", BitIndex::Bit0), "Bit0");
assert_eq!(format!("{}", BitIndex::Bit3), "Bit3");
assert_eq!(format!("{}", BitIndex::Bit7), "Bit7");
assert_eq!(format!("{}", BitIndex::LSB), "Bit0");
}
#[test]
fn test_round_trip_conversion() {
for &bit_index in BitIndex::all() {
let as_u8 = u8::from(bit_index);
let back_to_enum = BitIndex::try_from(as_u8).unwrap();
assert_eq!(bit_index, back_to_enum);
}
}
}