windows-api-utils 0.2.0

Windows API utilities for coordinate conversion, bit operations, and message parameter handling with feature gating
Documentation
//! Bit manipulation utilities.
//!
//! This module provides utilities for working with high and low
//! words/bytes of integers, commonly used in Windows API programming.
//!
//! Requires the `bit-ops` feature to be enabled.

use core::fmt;

/// Utility for working with high and low words of 32-bit values.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LowHighWord {
    value: u32,
}

impl LowHighWord {
    /// Creates a new LowHighWord from a 32-bit value.
    pub const fn new(value: u32) -> Self {
        Self { value }
    }

    /// Extracts the low-order word (bits 0-15).
    pub const fn loword(&self) -> u16 {
        (self.value & 0xFFFF) as u16
    }

    /// Extracts the high-order word (bits 16-31).
    pub const fn hiword(&self) -> u16 {
        ((self.value >> 16) & 0xFFFF) as u16
    }

    /// Creates a LowHighWord from high and low words.
    pub const fn from_parts(high: u16, low: u16) -> Self {
        Self {
            value: ((high as u32) << 16) | (low as u32),
        }
    }

    /// Returns the underlying 32-bit value.
    pub const fn value(&self) -> u32 {
        self.value
    }

    /// Extracts the low-order word as a signed 16-bit value.
    pub const fn loword_signed(&self) -> i16 {
        self.loword() as i16
    }

    /// Extracts the high-order word as a signed 16-bit value.
    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()
        )
    }
}

/// Extracts the low-order word from a 32-bit value.
pub const fn loword(value: u32) -> u16 {
    (value & 0xFFFF) as u16
}

/// Extracts the high-order word from a 32-bit value.
pub const fn hiword(value: u32) -> u16 {
    ((value >> 16) & 0xFFFF) as u16
}

/// Extracts the low-order byte from a 16-bit value.
pub const fn lobyte(value: u16) -> u8 {
    (value & 0xFF) as u8
}

/// Extracts the high-order byte from a 16-bit value.
pub const fn hibyte(value: u16) -> u8 {
    ((value >> 8) & 0xFF) as u8
}

/// Makes a 32-bit value from two 16-bit values.
pub const fn make_long(high: u16, low: u16) -> u32 {
    ((high as u32) << 16) | (low as u32)
}

/// Makes a 16-bit value from two 8-bit values.
pub const fn make_word(high: u8, low: u8) -> u16 {
    ((high as u16) << 8) | (low as u16)
}

/// Utility functions for bit manipulation.
pub struct BitUtils;

impl BitUtils {
    /// Extracts bits from a value.
    pub const fn get_bits(value: u32, offset: u8, length: u8) -> u32 {
        (value >> offset) & ((1 << length) - 1)
    }

    /// Sets bits in a value.
    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)
    }

    /// Checks if a specific bit is set.
    pub const fn is_bit_set(value: u32, bit: u8) -> bool {
        (value & (1 << bit)) != 0
    }

    /// Sets a specific bit.
    pub const fn set_bit(value: u32, bit: u8) -> u32 {
        value | (1 << bit)
    }

    /// Clears a specific bit.
    pub const fn clear_bit(value: u32, bit: u8) -> u32 {
        value & !(1 << bit)
    }

    /// Toggles a specific 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);
    }
}