//! Morton/Z-order interleaving of two `u128` values into a [`U256`].
use super::U256;

impl U256 {
    /// Interleaves two `u128` coordinates into a single [`U256`] Morton code.
    ///
    /// Bits of `x` occupy even positions (0, 2, 4, ..., 254) and bits of `y`
    /// occupy odd positions (1, 3, 5, ..., 255). This is equivalent to
    /// `from_u128_dilated_even(x) | from_u128_dilated_odd(y)`.
    ///
    /// The OR is safe because the two dilations occupy disjoint bit positions.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    ///
    /// // x=0b11, y=0b10 → interleaved = 0b1101
    /// let z = U256::interleave(0b11, 0b10);
    /// assert_eq!(z, U256::from_be_limbs([0, 0, 0, 0b1101]));
    /// ```
    #[inline]
    pub const fn interleave(x: u128, y: u128) -> U256 {
        let even = Self::from_u128_dilated_even(x);
        let odd = Self::from_u128_dilated_odd(y);

        U256([
            even.0[0] | odd.0[0],
            even.0[1] | odd.0[1],
            even.0[2] | odd.0[2],
            even.0[3] | odd.0[3],
        ])
    }
}

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

    /// Interleaving two zeros produces zero.
    #[test]
    fn zero_zero() {
        assert_eq!(U256::interleave(0, 0), U256::ZERO);
    }

    /// Interleaving x=1, y=0 places bit at position 0.
    #[test]
    fn x_one_y_zero() {
        assert_eq!(
            U256::interleave(1, 0),
            U256::from_u128_dilated_even(1),
        );
    }

    /// Interleaving x=0, y=1 places bit at position 1.
    #[test]
    fn x_zero_y_one() {
        assert_eq!(
            U256::interleave(0, 1),
            U256::from_u128_dilated_odd(1),
        );
    }

    /// Manual verification: x=0b11, y=0b10 → 0b1101.
    #[test]
    fn manual_bits() {
        let z = U256::interleave(0b11, 0b10);
        // x bit0=1 → pos0=1, x bit1=1 → pos2=1
        // y bit0=0 → pos1=0, y bit1=1 → pos3=1
        // Result: 0b1101 = 13
        assert_eq!(z, U256::from_be_limbs([0, 0, 0, 0b1101]));
    }

    /// Interleaving max values fills all 256 bits.
    #[test]
    fn max_max() {
        assert_eq!(U256::interleave(u128::MAX, u128::MAX), U256::MAX);
    }

    /// Equivalence with explicit dilate-then-OR.
    #[test]
    fn matches_dilate_or() {
        let x: u128 = 0xABCD_1234_5678_9ABC;
        let y: u128 = 0xDEF0_CAFE_BABE_DEAD;
        let interleaved = U256::interleave(x, y);
        let manual = U256::from_u128_dilated_even(x) | U256::from_u128_dilated_odd(y);
        assert_eq!(interleaved, manual);
    }
}
