//! Construction of a [`U512`] from a 64-byte big-endian array.
use super::U512;

impl U512 {
    /// Creates a new [`U512`] from a 64-byte array in big-endian order.
    ///
    /// Bytes `[0..8]` become limb `w0` (most significant), bytes `[8..16]`
    /// become `w1`, and so on through bytes `[56..64]` which become `w7`
    /// (least significant).
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u512::U512;
    ///
    /// let mut bytes = [0u8; 64];
    /// bytes[63] = 1;
    /// assert_eq!(U512::from_be_bytes(bytes), U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 1]));
    /// ```
    #[inline]
    pub const fn from_be_bytes(bytes: [u8; 64]) -> Self {
        let w0 = u64::from_be_bytes([
            bytes[0], bytes[1], bytes[2], bytes[3],
            bytes[4], bytes[5], bytes[6], bytes[7],
        ]);
        let w1 = u64::from_be_bytes([
            bytes[8], bytes[9], bytes[10], bytes[11],
            bytes[12], bytes[13], bytes[14], bytes[15],
        ]);
        let w2 = u64::from_be_bytes([
            bytes[16], bytes[17], bytes[18], bytes[19],
            bytes[20], bytes[21], bytes[22], bytes[23],
        ]);
        let w3 = u64::from_be_bytes([
            bytes[24], bytes[25], bytes[26], bytes[27],
            bytes[28], bytes[29], bytes[30], bytes[31],
        ]);
        let w4 = u64::from_be_bytes([
            bytes[32], bytes[33], bytes[34], bytes[35],
            bytes[36], bytes[37], bytes[38], bytes[39],
        ]);
        let w5 = u64::from_be_bytes([
            bytes[40], bytes[41], bytes[42], bytes[43],
            bytes[44], bytes[45], bytes[46], bytes[47],
        ]);
        let w6 = u64::from_be_bytes([
            bytes[48], bytes[49], bytes[50], bytes[51],
            bytes[52], bytes[53], bytes[54], bytes[55],
        ]);
        let w7 = u64::from_be_bytes([
            bytes[56], bytes[57], bytes[58], bytes[59],
            bytes[60], bytes[61], bytes[62], bytes[63],
        ]);
        Self([w7, w6, w5, w4, w3, w2, w1, w0])
    }
}

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

    /// All zeros produces the zero value.
    #[test]
    fn zero() {
        assert_eq!(
            U512::from_be_bytes([0; 64]),
            U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 0]),
        );
    }

    /// All ones produces the maximum value.
    #[test]
    fn max() {
        assert_eq!(U512::from_be_bytes([0xFF; 64]), U512::MAX);
    }

    /// Byte 63 (least significant) maps to the low bit of limb w7.
    #[test]
    fn single_lsb() {
        let mut bytes = [0u8; 64];
        bytes[63] = 1;
        assert_eq!(
            U512::from_be_bytes(bytes),
            U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 1]),
        );
    }

    /// Byte 0 (most significant) maps to the high bit of limb w0.
    #[test]
    fn single_msb() {
        let mut bytes = [0u8; 64];
        bytes[0] = 0x80;
        assert_eq!(
            U512::from_be_bytes(bytes),
            U512::from_be_limbs([0x8000000000000000, 0, 0, 0, 0, 0, 0, 0]),
        );
    }

    /// Boundary between w3 and w4 at bytes 31/32.
    #[test]
    fn limb_boundary() {
        let mut bytes = [0u8; 64];
        bytes[31] = 1;
        bytes[32] = 1;
        assert_eq!(
            U512::from_be_bytes(bytes),
            U512::from_be_limbs([0, 0, 0, 1, 0x0100000000000000, 0, 0, 0]),
        );
    }
}
