imagnum 0.1.21

A Rust library providing versatile numeric types supporting integers and floats designed for the Lucia programming language.
Documentation
#[allow(unused_imports)]
use crate::foundation::{Int, Float, NumberKind, NAN_FLOAT, NAN_INT};
#[allow(unused_imports)]
use crate::math::{
    ERR_UNIMPLEMENTED,
    ERR_INVALID_FORMAT,
    ERR_DIV_BY_ZERO,
    ERR_NEGATIVE_RESULT,
    ERR_NEGATIVE_SQRT,
    ERR_NUMBER_TOO_LARGE
};
use std::ops::{
    Add, Sub, Mul, Div, Rem, Neg,
    AddAssign, SubAssign, MulAssign, DivAssign, RemAssign,
};
use std::cmp::{Ordering, PartialOrd};
use std::fmt::{Display, Formatter, Result as FmtResult};

impl Add for Int {
    type Output = Result<Self, i16>;

    fn add(self, other: Self) -> Self::Output {
        self._add(&other.clone())
    }
}

impl Sub for Int {
    type Output = Result<Self, i16>;

    fn sub(self, other: Self) -> Self::Output {
        self._sub(&other.clone())
    }
}

impl Mul for Int {
    type Output = Result<Self, i16>;

    fn mul(self, other: Self) -> Self::Output {
        self._mul(&other.clone())
    }
}

impl Div for Int {
    type Output = Result<Self, i16>;

    fn div(self, other: Self) -> Self::Output {
        self._div(&other.clone())
    }
}

impl Rem for Int {
    type Output = Result<Self, i16>;

    fn rem(self, other: Self) -> Self::Output {
        self._modulo(&other.clone())
    }
}

impl Neg for Int {
    type Output = Self;

    fn neg(self) -> Self::Output {
        Int::new(self.digits, !self.negative, self.kind)
    }
}

impl AddAssign for Int {
    fn add_assign(&mut self, other: Self) {
        *self = self._add(&other).unwrap_or_else(|_| NAN_INT.clone());
    }
}

impl SubAssign for Int {
    fn sub_assign(&mut self, other: Self) {
        *self = self._sub(&other).unwrap_or_else(|_| NAN_INT.clone());
    }
}

impl MulAssign for Int {
    fn mul_assign(&mut self, other: Self) {
        *self = self._mul(&other).unwrap_or_else(|_| NAN_INT.clone());
    }
}

impl DivAssign for Int {
    fn div_assign(&mut self, other: Self) {
        *self = self._div(&other).unwrap_or_else(|_| NAN_INT.clone());
    }
}

impl RemAssign for Int {
    fn rem_assign(&mut self, other: Self) {
        *self = self._modulo(&other).unwrap_or_else(|_| NAN_INT.clone());
    }
}

impl PartialOrd for Int {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.negative && !other.negative {
            return Some(Ordering::Less);
        }
        if !self.negative && other.negative {
            return Some(Ordering::Greater);
        }

        let self_digits = self.digits.trim_start_matches('0');
        let other_digits = other.digits.trim_start_matches('0');

        let len_cmp = self_digits.len().cmp(&other_digits.len());

        if len_cmp != Ordering::Equal {
            return if self.negative {
                Some(len_cmp.reverse())
            } else {
                Some(len_cmp)
            };
        }

        for (a, b) in self_digits.chars().zip(other_digits.chars()) {
            if a != b {
                let cmp = a.cmp(&b);
                return if self.negative {
                    Some(cmp.reverse())
                } else {
                    Some(cmp)
                };
            }
        }

        Some(Ordering::Equal)
    }
}


impl Display for Int {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        if self.kind == NumberKind::NaN {
            write!(f, "NaN")?;
            return Ok(());
        } else if self.kind == NumberKind::Infinity {
            write!(f, "Infinity")?;
            return Ok(());
        } else if self.kind == NumberKind::NegInfinity {
            write!(f, "-Infinity")?;
            return Ok(());
        }
        if self.negative {
            write!(f, "-")?;
        }
        write!(f, "{}", self.digits)
    }
}

impl Add for Float {
    type Output = Result<Self, i16>;

    fn add(self, other: Self) -> Self::Output {
        self._add(&other.clone())
    }
}

impl Sub for Float {
    type Output = Result<Self, i16>;

    fn sub(self, other: Self) -> Self::Output {
        self._sub(&other.clone())
    }
}

impl Mul for Float {
    type Output = Result<Self, i16>;

    fn mul(self, other: Self) -> Self::Output {
        self._mul(&other.clone())
    }
}

impl Div for Float {
    type Output = Result<Self, i16>;

    fn div(self, other: Self) -> Self::Output {
        self._div(&other.clone())
    }
}

impl Rem for Float {
    type Output = Result<Self, i16>;

    fn rem(self, other: Self) -> Self::Output {
        self._modulo(&other.clone())
    }
}

impl Neg for Float {
    type Output = Self;

    fn neg(self) -> Self::Output {
        Float::new(self.mantissa, self.exponent, !self.negative, self.kind)
    }
}

impl AddAssign for Float {
    fn add_assign(&mut self, other: Self) {
        *self = self._add(&other).unwrap_or_else(|_| NAN_FLOAT.clone());
    }
}

impl SubAssign for Float {
    fn sub_assign(&mut self, other: Self) {
        *self = self._sub(&other).unwrap_or_else(|_| NAN_FLOAT.clone());
    }
}

impl MulAssign for Float {
    fn mul_assign(&mut self, other: Self) {
        *self = self._mul(&other).unwrap_or_else(|_| NAN_FLOAT.clone());
    }
}

impl DivAssign for Float {
    fn div_assign(&mut self, other: Self) {
        *self = self._div(&other).unwrap_or_else(|_| NAN_FLOAT.clone());
    }
}

impl RemAssign for Float {
    fn rem_assign(&mut self, other: Self) {
        *self = self._modulo(&other).unwrap_or_else(|_| NAN_FLOAT.clone());
    }
}

impl PartialOrd for Float {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.negative && !other.negative {
            return Some(Ordering::Less);
        }
        if !self.negative && other.negative {
            return Some(Ordering::Greater);
        }

        let sign = if self.negative { -1 } else { 1 };

        let exp_cmp = self.exponent.cmp(&other.exponent);
        if exp_cmp != Ordering::Equal {
            return Some(if sign == 1 { exp_cmp } else { exp_cmp.reverse() });
        }

        let self_man = self.mantissa.trim_start_matches('0');
        let other_man = other.mantissa.trim_start_matches('0');

        let len_cmp = self_man.len().cmp(&other_man.len());
        if len_cmp != Ordering::Equal {
            return Some(if sign == 1 { len_cmp } else { len_cmp.reverse() });
        }

        for (a, b) in self_man.chars().zip(other_man.chars()) {
            if a != b {
                let cmp = a.cmp(&b);
                return Some(if sign == 1 { cmp } else { cmp.reverse() });
            }
        }

        Some(Ordering::Equal)
    }
}

impl Display for Float {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        if self.kind == NumberKind::NaN {
            write!(f, "NaN")?;
            return Ok(());
        } else if self.kind == NumberKind::Infinity {
            write!(f, "Infinity")?;
            return Ok(());
        } else if self.kind == NumberKind::NegInfinity {
            write!(f, "-Infinity")?;
            return Ok(());
        }

        if self.negative {
            write!(f, "-")?;
        }

        if self.exponent >= -50 && self.exponent <= 50 {
            let mantissa = self.mantissa.trim_start_matches('0');
            let mantissa = if mantissa.is_empty() { "0" } else { mantissa };

            let exp = self.exponent;
            if exp == 0 {
                write!(f, "{}", mantissa)?;
            } else if exp > 0 {
                write!(f, "{}{}", mantissa, "0".repeat(exp as usize))?;
            } else {
                let mantissa_len = mantissa.len() as i64;
                let point_pos = mantissa_len + (exp as i64); // cast to i64

                if point_pos > 0 {
                    let (int_part, frac_part) = mantissa.split_at(point_pos as usize);
                    write!(f, "{}.{}", int_part, frac_part)?;
                } else {
                    write!(f, "0.{}{}", "0".repeat((-point_pos) as usize), mantissa)?;
                }
            }
        } else {
            write!(f, "{}e{}", self.mantissa, self.exponent)?;
        }

        if self.kind == NumberKind::Irrational {
            write!(f, "...")?;
        }

        Ok(())
    }
}