//! Count of leading zero bytes in a [`U256`].
use super::U256;

impl U256 {
    /// Returns the number of leading zero bytes in the 256-bit value.
    ///
    /// Counts full zero bytes from the most significant position.
    /// Returns 32 for zero, 0 when the most significant byte is non-zero.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    ///
    /// assert_eq!(U256::from_be_limbs([0, 0, 0, 0]).leading_zero_bytes(), 32);
    /// assert_eq!(U256::from_be_limbs([0, 0, 0, 1]).leading_zero_bytes(), 31);
    /// ```
    #[inline]
    pub const fn leading_zero_bytes(&self) -> u32 {
        if self.0[3] != 0 {
            return self.0[3].leading_zeros() / 8;
        }
        if self.0[2] != 0 {
            return 8 + self.0[2].leading_zeros() / 8;
        }
        if self.0[1] != 0 {
            return 16 + self.0[1].leading_zeros() / 8;
        }
        if self.0[0] != 0 {
            return 24 + self.0[0].leading_zeros() / 8;
        }
        32
    }
}

#[cfg(test)]
mod ai_tests {
    use super::*;
    /// Zero has 32 leading zero bytes.
    #[test]
    fn zero() {
        assert_eq!(U256::ZERO.leading_zero_bytes(), 32);
    }

    /// One has 31 leading zero bytes (only the last byte is non-zero).
    #[test]
    fn one() {
        assert_eq!(U256::ONE.leading_zero_bytes(), 31);
    }

    /// Max value has no leading zero bytes.
    #[test]
    fn max() {
        let max = U256::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
        assert_eq!(max.leading_zero_bytes(), 0);
    }

    /// Value with non-zero second limb has 8 + leading zeros of that limb.
    #[test]
    fn second_limb() {
        assert_eq!(U256::from_be_limbs([0, 1, 0, 0]).leading_zero_bytes(), 15);
    }

    /// Value with non-zero third limb.
    #[test]
    fn third_limb() {
        assert_eq!(
            U256::from_be_limbs([0, 0, 0x100, 0]).leading_zero_bytes(),
            22
        );
    }

    /// Value filling first byte exactly.
    #[test]
    fn first_byte_full() {
        assert_eq!(
            U256::from_be_limbs([0xFF00000000000000, 0, 0, 0]).leading_zero_bytes(),
            0,
        );
    }
}
