use alloy::primitives::Uint;
pub trait BitMath {
#[must_use]
fn most_significant_bit(self) -> usize;
#[must_use]
fn least_significant_bit(self) -> usize;
}
impl<const BITS: usize, const LIMBS: usize> BitMath for Uint<BITS, LIMBS> {
#[inline]
fn most_significant_bit(self) -> usize {
most_significant_bit(self)
}
#[inline]
fn least_significant_bit(self) -> usize {
least_significant_bit(self)
}
}
#[inline]
#[must_use]
pub fn most_significant_bit<const BITS: usize, const LIMBS: usize>(x: Uint<BITS, LIMBS>) -> usize {
BITS - 1 - x.leading_zeros()
}
#[inline]
#[must_use]
pub fn least_significant_bit<const BITS: usize, const LIMBS: usize>(x: Uint<BITS, LIMBS>) -> usize {
x.trailing_zeros()
}
#[cfg(test)]
mod tests {
use super::*;
use alloy::primitives::{uint, U256};
const ONE: U256 = uint!(1_U256);
#[test]
#[should_panic(expected = "overflow")]
fn most_significant_bit_throws_for_zero() {
let _ = most_significant_bit(U256::ZERO);
}
#[test]
fn test_most_significant_bit() {
for i in 0..=255 {
let x = ONE << i;
assert_eq!(most_significant_bit(x), i);
}
for i in 1..=255 {
let x = (ONE << i) - ONE;
assert_eq!(most_significant_bit(x), i - 1);
}
assert_eq!(most_significant_bit(U256::MAX), 255);
}
#[test]
fn test_least_significant_bit() {
for i in 0..=255 {
let x = ONE << i;
assert_eq!(least_significant_bit(x), i);
}
for i in 1..=255 {
let x = (ONE << i) - ONE;
assert_eq!(least_significant_bit(x), 0);
}
assert_eq!(least_significant_bit(U256::MAX), 0);
}
}