#![macro_use]
pub struct BitRange {
pub msb_index: u32,
pub lsb_index: u32,
}
pub trait BitRangeExt<T> {
fn get_mask(&self) -> T;
fn is_valid(&self) -> bool;
fn check(&self) {
assert!(self.is_valid(), "Invalid BitRange");
}
}
const MAX_U32_BIT_INDEX: u32 = 31;
impl BitRangeExt<u32> for BitRange {
fn get_mask(&self) -> u32 {
self.check();
((((1_u64) << (self.msb_index - self.lsb_index + 1)) - 1) << self.lsb_index) as u32
}
fn is_valid(&self) -> bool {
self.msb_index >= self.lsb_index && self.msb_index <= MAX_U32_BIT_INDEX
}
}
macro_rules! bit_range {
($msb_index:expr, $lsb_index:expr) => {
BitRange {
msb_index: $msb_index,
lsb_index: $lsb_index,
}
};
}
pub trait BitHelper {
fn read_bit(&self, pos: u32) -> bool;
fn write_bit(&mut self, pos: u32, val: bool) -> &mut Self;
#[must_use]
fn read_bits_in_range(&self, bit_range: &BitRange) -> Self;
fn write_bits_in_range(&mut self, bit_range: &BitRange, val: Self) -> &mut Self;
}
impl BitHelper for u32 {
fn read_bit(&self, pos: u32) -> bool {
assert!(pos <= MAX_U32_BIT_INDEX, "Invalid pos");
(*self & (1 << pos)) > 0
}
fn write_bit(&mut self, pos: u32, val: bool) -> &mut Self {
assert!(pos <= MAX_U32_BIT_INDEX, "Invalid pos");
*self &= !(1 << pos);
*self |= (val as u32) << pos;
self
}
fn read_bits_in_range(&self, range: &BitRange) -> Self {
range.check();
(self & range.get_mask()) >> range.lsb_index
}
fn write_bits_in_range(&mut self, range: &BitRange, val: Self) -> &mut Self {
range.check();
let mask = range.get_mask();
let max_val = mask >> range.lsb_index;
assert!(val <= max_val, "Invalid val");
*self &= !mask;
*self |= val << range.lsb_index;
self
}
}
#[cfg(test)]
mod tests {
use crate::bit_helper::*;
#[test]
#[should_panic]
fn test_invalid_msb_index() {
let range = BitRange {
msb_index: 32,
lsb_index: 2,
};
range.check();
}
#[test]
#[should_panic]
fn test_invalid_range() {
let range = BitRange {
msb_index: 10,
lsb_index: 15,
};
range.check();
}
#[test]
#[should_panic]
fn test_invalid_write_bit() {
let mut val: u32 = 0;
val.write_bit(32, true);
}
#[test]
fn test_simple_write_bit() {
let mut val: u32 = 0;
val.write_bit(5, true);
assert!(val == 1 << 5);
val = 1 << 5;
val.write_bit(5, false);
assert!(val == 0);
}
#[test]
#[should_panic]
fn test_invalid_read_bit() {
let val: u32 = 0;
val.read_bit(32);
}
#[test]
fn test_simple_read_bit() {
let val: u32 = 0b10_0000;
assert!(val.read_bit(5));
assert!(!val.read_bit(4));
}
#[test]
fn test_chained_write_bit() {
let mut val: u32 = 1 << 12;
val.write_bit(5, true)
.write_bit(10, true)
.write_bit(15, true)
.write_bit(12, false);
assert!(val == 1 << 5 | 1 << 10 | 1 << 15);
}
#[test]
fn test_get_u32_mask_for_range() {
assert!(
BitRange {
msb_index: 3,
lsb_index: 2
}
.get_mask()
== 0b1100
);
assert!(
BitRange {
msb_index: 4,
lsb_index: 2
}
.get_mask()
== 0b11100
);
assert!(
BitRange {
msb_index: 5,
lsb_index: 2
}
.get_mask()
== 0b11_1100
);
assert!(
BitRange {
msb_index: 6,
lsb_index: 2
}
.get_mask()
== 0b111_1100
);
assert!(
BitRange {
msb_index: 7,
lsb_index: 2
}
.get_mask()
== 0b1111_1100
);
}
#[test]
#[should_panic]
fn test_invalid_read_bits() {
let val: u32 = 30;
let _ = val.read_bits_in_range(&BitRange {
msb_index: 32,
lsb_index: 2,
});
}
#[test]
fn test_read_bits() {
let val: u32 = 0b1000_0000_0000_0000_0011_0101_0001_0000;
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 3,
lsb_index: 2
}) == 0b00
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 4,
lsb_index: 2
}) == 0b100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 5,
lsb_index: 2
}) == 0b0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 6,
lsb_index: 2
}) == 0b00100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 7,
lsb_index: 2
}) == 0b00_0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 8,
lsb_index: 2
}) == 0b100_0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 9,
lsb_index: 2
}) == 0b0100_0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 10,
lsb_index: 2
}) == 0b1_0100_0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 11,
lsb_index: 2
}) == 0b01_0100_0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 12,
lsb_index: 2
}) == 0b101_0100_0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 13,
lsb_index: 2
}) == 0b1101_0100_0100
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 31,
lsb_index: 15
}) == 0b1_0000_0000_0000_0000
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 14,
lsb_index: 0
}) == 0b011_0101_0001_0000
);
assert!(
val.read_bits_in_range(&BitRange {
msb_index: 31,
lsb_index: 0
}) == 0b1000_0000_0000_0000_0011_0101_0001_0000
);
}
#[test]
#[should_panic]
fn test_invalid_write_bits() {
let mut val: u32 = 0;
val.write_bits_in_range(
&BitRange {
msb_index: 32,
lsb_index: 2,
},
0b100,
);
}
#[test]
#[should_panic]
fn test_overflow_write_bits() {
let mut val: u32 = 0;
val.write_bits_in_range(
&BitRange {
msb_index: 3,
lsb_index: 2,
},
0b100,
);
}
#[test]
fn test_simple_write_bits() {
let mut val: u32 = 0;
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 3,
lsb_index: 2
},
0b00
) == &0b0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 4,
lsb_index: 2
},
0b100
) == &0b10000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 5,
lsb_index: 2
},
0b0100
) == &0b01_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 6,
lsb_index: 2
},
0b0_0100
) == &0b001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 7,
lsb_index: 2
},
0b00_0100
) == &0b0001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 8,
lsb_index: 2
},
0b100_0100
) == &0b1_0001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 9,
lsb_index: 2
},
0b0100_0100
) == &0b01_0001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 10,
lsb_index: 2
},
0b1_0100_0100
) == &0b101_0001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 11,
lsb_index: 2
},
0b01_0100_0100
) == &0b0101_0001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 12,
lsb_index: 2
},
0b101_0100_0100
) == &0b1_0101_0001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 13,
lsb_index: 2
},
0b1101_0100_0100
) == &0b11_0101_0001_0000
);
val = 0;
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 31,
lsb_index: 15
},
0b1_0000_0000_0000_0000
) == &0b1000_0000_0000_0000_0000_0000_0000_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 14,
lsb_index: 0
},
0b011_0101_0001_0000
) == &0b1000_0000_0000_0000_0011_0101_0001_0000
);
assert!(
val.write_bits_in_range(
&BitRange {
msb_index: 31,
lsb_index: 0
},
0b1000_0000_0000_0000_0011_0101_0001_0000
) == &0b1000_0000_0000_0000_0011_0101_0001_0000
);
}
#[test]
fn test_chained_write_bits() {
let mut val: u32 = 0;
val.write_bits_in_range(
&BitRange {
msb_index: 4,
lsb_index: 2,
},
0b100,
)
.write_bits_in_range(
&BitRange {
msb_index: 12,
lsb_index: 10,
},
0b110,
)
.write_bits_in_range(
&BitRange {
msb_index: 24,
lsb_index: 20,
},
0b10101,
)
.write_bits_in_range(
&BitRange {
msb_index: 31,
lsb_index: 28,
},
0b1011,
);
assert!(val == 0b1011_0001_0101_0000_0001_1000_0001_0000);
}
}