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

impl U256 {
    /// Deinterleaves a [`U256`] Morton code into two `u128` coordinates.
    ///
    /// Returns `(x, y)` where `x` contains the bits from even positions
    /// (0, 2, 4, ..., 254) and `y` contains the bits from odd positions
    /// (1, 3, 5, ..., 255). This is the inverse of
    /// [`interleave`](U256::interleave):
    /// `U256::interleave(x, y).deinterleave() == (x, y)`.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    ///
    /// let (x, y) = U256::interleave(42, 99).deinterleave();
    /// assert_eq!(x, 42);
    /// assert_eq!(y, 99);
    /// ```
    #[inline]
    pub const fn deinterleave(&self) -> (u128, u128) {
        (self.undilate_even(), self.undilate_odd())
    }
}

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

    /// Deinterleaving zero produces (0, 0).
    #[test]
    fn zero() {
        assert_eq!(U256::ZERO.deinterleave(), (0, 0));
    }

    /// Round-trip: interleave then deinterleave recovers both coordinates.
    #[test]
    fn round_trip() {
        let x: u128 = 0xDEAD_BEEF_CAFE_BABE_1234_5678_9ABC_DEF0;
        let y: u128 = 0x0123_4567_89AB_CDEF_FEDC_BA98_7654_3210;
        assert_eq!(U256::interleave(x, y).deinterleave(), (x, y));
    }

    /// Deinterleaving an even-only value returns (x, 0).
    #[test]
    fn even_only() {
        let x: u128 = 0xCAFE_BABE;
        let v = U256::from_u128_dilated_even(x);
        assert_eq!(v.deinterleave(), (x, 0));
    }

    /// Deinterleaving an odd-only value returns (0, y).
    #[test]
    fn odd_only() {
        let y: u128 = 0xDEAD_BEEF;
        let v = U256::from_u128_dilated_odd(y);
        assert_eq!(v.deinterleave(), (0, y));
    }

    /// Deinterleaving MAX gives (u128::MAX, u128::MAX).
    #[test]
    fn max() {
        assert_eq!(U256::MAX.deinterleave(), (u128::MAX, u128::MAX));
    }

    /// Round-trip with both coordinates at maximum.
    #[test]
    fn round_trip_max() {
        assert_eq!(
            U256::interleave(u128::MAX, u128::MAX).deinterleave(),
            (u128::MAX, u128::MAX),
        );
    }
}
