//! Morton undilation extracting odd bit positions from a [`U256`] into a `u128`.
use super::U256;

impl U256 {
    /// Extracts bits at odd positions (1, 3, 5, ..., 255) and compacts them
    /// into a `u128`.
    ///
    /// Bit `2i+1` of the [`U256`] maps to bit `i` of the result. This is the
    /// inverse of [`from_u128_dilated_odd`](U256::from_u128_dilated_odd):
    /// `U256::from_u128_dilated_odd(v).undilate_odd() == v`.
    ///
    /// Internally shifts each limb right by 1 to move odd positions into even
    /// positions, then delegates to the even-position undilation cascade.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    ///
    /// let v = U256::from_u128_dilated_odd(0xDEAD_BEEF);
    /// assert_eq!(v.undilate_odd(), 0xDEAD_BEEF);
    /// ```
    #[inline]
    pub const fn undilate_odd(&self) -> u128 {
        let shifted = U256([
            self.0[0] >> 1,
            self.0[1] >> 1,
            self.0[2] >> 1,
            self.0[3] >> 1,
        ]);
        shifted.undilate_even()
    }
}

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

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

    /// Round-trip: dilate odd then undilate odd recovers the original.
    #[test]
    fn round_trip_one() {
        assert_eq!(U256::from_u128_dilated_odd(1).undilate_odd(), 1);
    }

    /// Round-trip with a value spanning all four quarters.
    #[test]
    fn round_trip_cross_quarter() {
        let v: u128 = 0xDEAD_BEEF_CAFE_BABE_1234_5678_9ABC_DEF0;
        assert_eq!(U256::from_u128_dilated_odd(v).undilate_odd(), v);
    }

    /// Round-trip with u128::MAX.
    #[test]
    fn round_trip_max() {
        assert_eq!(
            U256::from_u128_dilated_odd(u128::MAX).undilate_odd(),
            u128::MAX,
        );
    }

    /// Even-only dilated value undilates to zero from odd positions.
    #[test]
    fn even_input_gives_zero() {
        let v = U256::from_u128_dilated_even(u128::MAX);
        assert_eq!(v.undilate_odd(), 0);
    }

    /// Single high bit: bit 255 (odd) → bit 127.
    #[test]
    fn bit_255_to_127() {
        let v = U256::from_u128_dilated_odd(1u128 << 127);
        assert_eq!(v.undilate_odd(), 1u128 << 127);
    }
}
