//! Checked 320-bit addition returning [`None`] on overflow.
use super::U320;

impl U320 {
    /// Computes `self + other`, returning `None` if the result would
    /// overflow 320 bits.
    ///
    /// Delegates to [`U320::overflowing_add`] and converts the overflow
    /// flag into an [`Option`].
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u320::U320;
    ///
    /// let a = U320::from_be_limbs([0, 0, 0, 0, 10]);
    /// let b = U320::from_be_limbs([0, 0, 0, 0, 20]);
    /// assert_eq!(a.checked_add(&b), Some(U320::from_be_limbs([0, 0, 0, 0, 30])));
    /// assert_eq!(U320::MAX.checked_add(&U320::ONE), None);
    /// ```
    #[inline]
    pub const fn checked_add(&self, other: &U320) -> Option<U320> {
        let (result, overflow) = self.overflowing_add(other);
        if overflow {
            None
        } else {
            Some(result)
        }
    }
}

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

    /// Non-overflowing addition returns Some.
    #[test]
    fn no_overflow() {
        let a = U320::from_be_limbs([0, 0, 0, 0, 10]);
        let b = U320::from_be_limbs([0, 0, 0, 0, 20]);
        assert_eq!(a.checked_add(&b), Some(U320::from_be_limbs([0, 0, 0, 0, 30])));
    }

    /// Overflowing addition returns None.
    #[test]
    fn overflow_returns_none() {
        assert_eq!(U320::MAX.checked_add(&U320::ONE), None);
    }

    /// Adding zero returns Some(self).
    #[test]
    fn add_zero() {
        let a = U320::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1111]);
        assert_eq!(a.checked_add(&U320::ZERO), Some(a));
    }

    /// MAX + MAX returns None.
    #[test]
    fn max_plus_max() {
        assert_eq!(U320::MAX.checked_add(&U320::MAX), None);
    }

    /// Large non-overflowing addition.
    #[test]
    fn large_no_overflow() {
        let a = U320::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
        let result = a.checked_add(&U320::ONE);
        assert_eq!(result, Some(U320::from_be_limbs([1, 0, 0, 0, 0])));
    }
}
