fastnum 0.7.4

Fast decimal numbers library
Documentation
use core::{
    fmt,
    fmt::{Display, Formatter},
};

use crate::{bint::UInt, decimal::dec::ControlBlock};

#[inline]
pub(crate) fn debug_print<const N: usize>(
    digits: &UInt<N>,
    cb: &ControlBlock,
    ty: &str,
    f: &mut Formatter,
) -> fmt::Result {
    if f.alternate() {
        debug_print_alternate(digits, cb, ty, f)
    } else {
        debug_print_default(digits, cb, ty, f)
    }
}

fn debug_print_alternate<const N: usize>(
    digits: &UInt<N>,
    cb: &ControlBlock,
    ty: &str,
    f: &mut Formatter,
) -> fmt::Result {
    if cb.is_nan() {
        return write!(f, "{ty}(NaN)");
    } else if cb.is_infinity() {
        return write!(f, "{ty}({}Inf)", cb.get_sign());
    }

    let alert = if cb.is_op_ok() { "" } else { "! " };
    write!(
        f,
        "{}({}{}{}e{})",
        ty,
        alert,
        cb.get_sign(),
        digits,
        cb.get_exponent()
    )
}

fn debug_print_default<const N: usize>(
    digits: &UInt<N>,
    cb: &ControlBlock,
    ty: &str,
    f: &mut Formatter,
) -> fmt::Result {
    write!(
        f,
        "{}(digits=[{:?}], exp=[{}], flags=[{}], signals=[{}], ctx=[{}], extra=[{}])",
        ty,
        digits,
        cb.get_exponent(),
        Flags(*cb),
        cb.get_signals(),
        cb.get_context(),
        cb.get_extra_precision()
    )
}

struct Flags(ControlBlock);

macro_rules! delimiter {
    ($delimiter: ident, $f: ident) => {
        #[allow(unused_assignments)]
        match $delimiter {
            true => {
                write!($f, ", ")?;
            }
            false => {
                $delimiter = true;
            }
        }
    };
}

impl Display for Flags {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let mut delimiter = false;

        if self.0.is_nan() {
            write!(f, "NAN")?;
            delimiter = true;
        }

        if self.0.is_negative() {
            delimiter!(delimiter, f);
            write!(f, "S")?;
        }

        if self.0.is_infinity() {
            delimiter!(delimiter, f);
            write!(f, "INF")?;
        }

        Ok(())
    }
}

macro_rules! type_name {
    ($t: literal) => {
        const {
            const PREFIX: &'static [u8] = $t.as_bytes();

            let buffer: &[u8] = &const {
                let mut buffer = [0; PREFIX.len() + usize::MAX.ilog10() as usize + 1];

                let mut i = buffer.len();
                let mut n = N * 64;

                while 0 < i && n != 0 {
                    i -= 1;

                    buffer[i] = (n % 10) as u8 + b'0';
                    n /= 10;
                }

                let mut j = PREFIX.len();
                while 0 < i && 0 < j {
                    i -= 1;
                    j -= 1;

                    buffer[i] = PREFIX[j];
                }

                buffer
            };

            let buffer_len = PREFIX.len() + (N * 64).ilog10() as usize + 1;

            match core::str::from_utf8(buffer.split_at(buffer.len() - buffer_len).1) {
                Ok(x) => x,
                Err(_) => panic!("buffer is always ascii"),
            }
        }
    };
}

pub(crate) use type_name;