cnfy-uint 0.2.3

Zero-dependency 256-bit unsigned integer arithmetic for cryptographic applications
Documentation
//! Uppercase hexadecimal formatting via [`fmt::UpperHex`].
use super::U320;
use core::fmt;

/// Formats a [`U320`] as an uppercase hexadecimal string without leading
/// zeros (except for the value zero itself, which formats as `"0"`).
///
/// Supports the `#` alternate flag for a `0x` prefix, matching the
/// standard library convention for integer types.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u320::U320;
///
/// let v = U320::from_be_limbs([0, 0, 0, 0, 255]);
/// assert_eq!(format!("{:X}", v), "FF");
/// assert_eq!(format!("{:#X}", v), "0xFF");
/// ```
impl fmt::UpperHex for U320 {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Iterate from MSB (index 4) to LSB (index 0)
        let mut first_nonzero = None;
        let mut i = 4;
        loop {
            if self.0[i] != 0 {
                first_nonzero = Some(i);
                break;
            }
            if i == 0 {
                break;
            }
            i -= 1;
        }

        match first_nonzero {
            None => {
                if f.alternate() {
                    f.write_str("0x0")
                } else {
                    f.write_str("0")
                }
            }
            Some(idx) => {
                if f.alternate() {
                    f.write_str("0x")?;
                }
                write!(f, "{:X}", self.0[idx])?;
                let mut j = idx;
                while j > 0 {
                    j -= 1;
                    write!(f, "{:016X}", self.0[j])?;
                }
                Ok(())
            }
        }
    }
}

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

    /// Zero formats as "0".
    #[test]
    fn zero() {
        assert_eq!(format!("{:X}", U320::ZERO), "0");
    }

    /// Zero with alternate flag formats as "0x0".
    #[test]
    fn zero_alternate() {
        assert_eq!(format!("{:#X}", U320::ZERO), "0x0");
    }

    /// Small value formats without leading zeros in uppercase.
    #[test]
    fn small_value() {
        let v = U320::from_be_limbs([0, 0, 0, 0, 0xAB]);
        assert_eq!(format!("{:X}", v), "AB");
    }

    /// Value spanning two limbs shows full padding on lower limb.
    #[test]
    fn two_limbs() {
        let v = U320::from_be_limbs([0, 0, 0, 1, 0]);
        assert_eq!(format!("{:X}", v), "10000000000000000");
    }

    /// All-max value fills all 80 hex digits.
    #[test]
    fn max_value() {
        let s = format!("{:X}", U320::MAX);
        assert_eq!(s.len(), 80);
        assert!(s.chars().all(|c| c == 'F'));
    }

    /// Alternate flag adds 0x prefix.
    #[test]
    fn alternate_prefix() {
        let v = U320::from_be_limbs([0, 0, 0, 0, 0xCAFE]);
        assert_eq!(format!("{:#X}", v), "0xCAFE");
    }

    /// ONE formats as "1".
    #[test]
    fn one() {
        assert_eq!(format!("{:X}", U320::ONE), "1");
    }
}