//! Left shift via the [`Shl`] trait.
use super::U256;
use core::ops::Shl;

/// Shifts the value left by `n` bits, zero-filling the low bits and
/// discarding bits shifted past position 255.
///
/// Delegates to [`U256::shl_bits`]. For shifts of 256 or more, the
/// result is zero.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u256::U256;
///
/// let a = U256::from_be_limbs([0, 0, 0, 1]);
/// assert_eq!(a << 3, U256::from_be_limbs([0, 0, 0, 8]));
/// ```
impl Shl<u32> for U256 {
    type Output = U256;

    #[inline]
    fn shl(self, rhs: u32) -> U256 {
        self.shl_bits(rhs)
    }
}

#[cfg(test)]
mod ai_tests {
    use super::*;

    /// Shift by zero is identity.
    #[test]
    fn identity() {
        let a = U256::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0]);
        assert_eq!(a << 0, a);
    }

    /// Shift by 1 doubles the value.
    #[test]
    fn shift_one() {
        assert_eq!(
            U256::from_be_limbs([0, 0, 0, 4]) << 1,
            U256::from_be_limbs([0, 0, 0, 8]),
        );
    }

    /// Shift by 64 moves one limb.
    #[test]
    fn one_limb() {
        let a = U256::from_be_limbs([0, 0, 0, 1]);
        assert_eq!(a << 64, U256::from_be_limbs([0, 0, 1, 0]));
    }

    /// Shift by 256 or more produces zero.
    #[test]
    fn full_shift() {
        assert_eq!(U256::MAX << 256, U256::ZERO);
        assert_eq!(U256::MAX << 300, U256::ZERO);
    }

    /// Matches shl_bits behavior.
    #[test]
    fn matches_shl_bits() {
        let a = U256::from_be_limbs([0, 0x1234, 0x5678, 0x9ABC]);
        assert_eq!(a << 17, a.shl_bits(17));
    }
}
