cnfy-uint 0.2.3

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

/// Formats a [`U384`] 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 384-bit width.
/// The value zero formats as `"0"`.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u384::U384;
///
/// let v = U384::from_be_limbs([0, 0, 0, 0, 0, 42]);
/// assert_eq!(format!("{}", v), "42");
/// assert_eq!(format!("{}", U384::ZERO), "0");
/// ```
impl fmt::Display for U384 {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.is_zero() {
            return f.write_str("0");
        }

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

        // Maximum 7 groups of 19 digits covers 133 digits (116 needed)
        let mut groups = [0u64; 7];
        let mut count = 0;
        let mut val = *self;

        while !val.is_zero() {
            let remainder = val.div_u64(DIVISOR);
            groups[count] = remainder;
            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!("{}", U384::ZERO), "0");
    }

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

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

    /// u64::MAX formats correctly.
    #[test]
    fn u64_max() {
        let v = U384::from_be_limbs([0, 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 = U384::from_be_limbs([0, 0, 0, 0, 0, 10_000_000_000_000_000_000]);
        assert_eq!(format!("{}", v), "10000000000000000000");
    }

    /// MAX value (2^384 - 1) has 116 decimal digits.
    #[test]
    fn max_value() {
        let s = format!("{}", U384::MAX);
        assert_eq!(s.len(), 116);
        assert_eq!(
            s,
            "39402006196394479212279040100143613805079739270465446667948293404245721771497210611414266254884915640806627990306815",
        );
    }

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