cnfy-uint 0.2.3

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

/// Formats a [`U320`] as a decimal string.
///
/// Uses repeated division by `10^19` (the largest power of 10 that fits
/// in a `u64`) to extract groups of up to 19 decimal digits at a time,
/// avoiding one-digit-at-a-time division over the full 320-bit width.
/// The value zero formats as `"0"`.
///
/// This is not a hot path — it uses a fixed-size stack buffer and
/// fills it from least significant to most significant digit group.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u320::U320;
///
/// let v = U320::from_be_limbs([0, 0, 0, 0, 42]);
/// assert_eq!(format!("{}", v), "42");
/// assert_eq!(format!("{}", U320::ZERO), "0");
/// ```
impl fmt::Display for U320 {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.is_zero() {
            return f.write_str("0");
        }

        // 2^320 - 1 has 97 decimal digits. We extract groups of up to
        // 19 digits (10^19 fits in u64) to minimize 320-bit divisions.
        const DIVISOR: u64 = 10_000_000_000_000_000_000; // 10^19
        const GROUP_WIDTH: usize = 19;

        // Maximum 6 groups of 19 digits covers 114 digits (97 needed)
        let mut groups = [0u64; 6];
        let mut count = 0;
        let mut val = *self;

        while !val.is_zero() {
            let rem = val.div_u64(DIVISOR);
            groups[count] = rem;
            count += 1;
        }

        // Write the most significant group without leading zeros
        write!(f, "{}", groups[count - 1])?;

        // Write remaining groups with zero-padding to 19 digits
        for i in (0..count - 1).rev() {
            write!(f, "{:0width$}", groups[i], width = GROUP_WIDTH)?;
        }

        Ok(())
    }
}

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

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

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

    /// Small value formats correctly.
    #[test]
    fn small() {
        assert_eq!(format!("{}", U320::from_be_limbs([0, 0, 0, 0, 42])), "42");
    }

    /// u64::MAX formats correctly.
    #[test]
    fn u64_max() {
        let v = U320::from_be_limbs([0, 0, 0, 0, u64::MAX]);
        assert_eq!(format!("{}", v), "18446744073709551615");
    }

    /// Power of 10 formats without spurious digits.
    #[test]
    fn power_of_ten() {
        let v = U320::from_be_limbs([0, 0, 0, 0, 10_000_000_000_000_000_000]);
        assert_eq!(format!("{}", v), "10000000000000000000");
    }

    /// MAX value (2^320 - 1) formats correctly.
    #[test]
    fn max_value() {
        let s = format!("{}", U320::MAX);
        // 2^320 - 1 = 2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936575
        assert_eq!(
            s,
            "2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936575",
        );
    }

    /// Value spanning multiple limbs.
    #[test]
    fn multi_limb() {
        // 2^64 = 18446744073709551616
        let v = U320::from_be_limbs([0, 0, 0, 1, 0]);
        assert_eq!(format!("{}", v), "18446744073709551616");
    }
}