use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LowHighWord {
value: u32,
}
impl LowHighWord {
pub const fn new(value: u32) -> Self {
Self { value }
}
pub const fn loword(&self) -> u16 {
(self.value & 0xFFFF) as u16
}
pub const fn hiword(&self) -> u16 {
((self.value >> 16) & 0xFFFF) as u16
}
pub const fn from_parts(high: u16, low: u16) -> Self {
Self {
value: ((high as u32) << 16) | (low as u32),
}
}
pub const fn value(&self) -> u32 {
self.value
}
pub const fn loword_signed(&self) -> i16 {
self.loword() as i16
}
pub const fn hiword_signed(&self) -> i16 {
self.hiword() as i16
}
}
impl From<u32> for LowHighWord {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl From<LowHighWord> for u32 {
fn from(lhw: LowHighWord) -> Self {
lhw.value
}
}
impl fmt::Display for LowHighWord {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"0x{:08X} (hi: 0x{:04X}, lo: 0x{:04X})",
self.value,
self.hiword(),
self.loword()
)
}
}
pub const fn loword(value: u32) -> u16 {
(value & 0xFFFF) as u16
}
pub const fn hiword(value: u32) -> u16 {
((value >> 16) & 0xFFFF) as u16
}
pub const fn lobyte(value: u16) -> u8 {
(value & 0xFF) as u8
}
pub const fn hibyte(value: u16) -> u8 {
((value >> 8) & 0xFF) as u8
}
pub const fn make_long(high: u16, low: u16) -> u32 {
((high as u32) << 16) | (low as u32)
}
pub const fn make_word(high: u8, low: u8) -> u16 {
((high as u16) << 8) | (low as u16)
}
pub struct BitUtils;
impl BitUtils {
pub const fn get_bits(value: u32, offset: u8, length: u8) -> u32 {
(value >> offset) & ((1 << length) - 1)
}
pub const fn set_bits(value: u32, bits: u32, offset: u8, length: u8) -> u32 {
let mask = ((1 << length) - 1) << offset;
(value & !mask) | ((bits << offset) & mask)
}
pub const fn is_bit_set(value: u32, bit: u8) -> bool {
(value & (1 << bit)) != 0
}
pub const fn set_bit(value: u32, bit: u8) -> u32 {
value | (1 << bit)
}
pub const fn clear_bit(value: u32, bit: u8) -> u32 {
value & !(1 << bit)
}
pub const fn toggle_bit(value: u32, bit: u8) -> u32 {
value ^ (1 << bit)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_loword_hiword() {
let value = 0x12345678;
assert_eq!(loword(value), 0x5678);
assert_eq!(hiword(value), 0x1234);
let lhw = LowHighWord::new(value);
assert_eq!(lhw.loword(), 0x5678);
assert_eq!(lhw.hiword(), 0x1234);
assert_eq!(lhw.value(), value);
}
#[test]
fn test_make_long() {
assert_eq!(make_long(0x1234, 0x5678), 0x12345678);
let lhw = LowHighWord::from_parts(0x1234, 0x5678);
assert_eq!(lhw.value(), 0x12345678);
}
#[test]
fn test_lobyte_hibyte() {
let value = 0x1234;
assert_eq!(lobyte(value), 0x34);
assert_eq!(hibyte(value), 0x12);
assert_eq!(make_word(0x12, 0x34), 0x1234);
}
#[test]
fn test_bit_operations() {
let value = 0b1010;
assert_eq!(BitUtils::get_bits(value, 1, 2), 0b01);
assert_eq!(BitUtils::set_bits(0, 0b11, 2, 2), 0b1100);
assert!(BitUtils::is_bit_set(value, 1));
assert_eq!(BitUtils::set_bit(value, 0), 0b1011);
assert_eq!(BitUtils::clear_bit(value, 1), 0b1000);
assert_eq!(BitUtils::toggle_bit(value, 0), 0b1011);
}
}