//! Significant bit count for [`U256`].
use super::U256;

impl U256 {
    /// Returns the number of significant bits in this value.
    ///
    /// Equivalent to `256 - leading_zeros_in_bits`. Returns 0 for zero,
    /// 1 for the value 1, and 256 for any value with the most significant
    /// bit set.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    ///
    /// assert_eq!(U256::from_be_limbs([0, 0, 0, 0]).bit_len(), 0);
    /// assert_eq!(U256::from_be_limbs([0, 0, 0, 1]).bit_len(), 1);
    /// assert_eq!(U256::from_be_limbs([0, 0, 0, 255]).bit_len(), 8);
    /// assert_eq!(U256::from_be_limbs([1, 0, 0, 0]).bit_len(), 193);
    /// ```
    #[inline]
    pub const fn bit_len(&self) -> u32 {
        if self.0[3] != 0 {
            256 - self.0[3].leading_zeros()
        } else if self.0[2] != 0 {
            192 - self.0[2].leading_zeros()
        } else if self.0[1] != 0 {
            128 - self.0[1].leading_zeros()
        } else if self.0[0] != 0 {
            64 - self.0[0].leading_zeros()
        } else {
            0
        }
    }
}

#[cfg(test)]
mod ai_tests {
    use super::*;
    const P: U256 = U256::from_be_limbs([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFEFFFFFC2F]);

    /// Zero has bit length 0.
    #[test]
    fn zero() {
        assert_eq!(U256::ZERO.bit_len(), 0);
    }

    /// Value 1 has bit length 1.
    #[test]
    fn one() {
        assert_eq!(U256::from_be_limbs([0, 0, 0, 1]).bit_len(), 1);
    }

    /// Powers of two have bit length equal to exponent + 1.
    #[test]
    fn powers_of_two() {
        assert_eq!(U256::from_be_limbs([0, 0, 0, 256]).bit_len(), 9);
        assert_eq!(U256::from_be_limbs([0, 0, 1, 0]).bit_len(), 65);
        assert_eq!(U256::from_be_limbs([0, 1, 0, 0]).bit_len(), 129);
        assert_eq!(U256::from_be_limbs([1, 0, 0, 0]).bit_len(), 193);
    }

    /// Max value has bit length 256.
    #[test]
    fn max_value() {
        let max = U256::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
        assert_eq!(max.bit_len(), 256);
    }

    /// secp256k1 P has 256 bits.
    #[test]
    fn secp256k1_p() {
        assert_eq!(P.bit_len(), 256);
    }

    /// Value 0xFF has 8 bits.
    #[test]
    fn byte_boundary() {
        assert_eq!(U256::from_be_limbs([0, 0, 0, 0xFF]).bit_len(), 8);
    }

    /// Each limb boundary is correct.
    #[test]
    fn limb_boundaries() {
        assert_eq!(U256::from_be_limbs([0, 0, 0, u64::MAX]).bit_len(), 64);
        assert_eq!(U256::from_be_limbs([0, 0, u64::MAX, 0]).bit_len(), 128);
        assert_eq!(U256::from_be_limbs([0, u64::MAX, 0, 0]).bit_len(), 192);
        assert_eq!(U256::from_be_limbs([u64::MAX, 0, 0, 0]).bit_len(), 256);
    }
}
