number-based 0.2.3

number-based is an attempt of mine to make working with number bases simple.
Documentation
use std::fmt::Display;
use std::ops::{Add, Div, Mul, Sub};
use std::str;

use crate::utils::{self, from_string};
use crate::{uBase, NumberBase};

use super::operations::*;

use crate::graphemes::grapheme_creation::GRAPHEMES;

#[allow(non_camel_case_types)]
#[derive(Debug, Clone)]
pub struct iBase {
    digits: Vec<u16>,
    base: u16,
}

impl NumberBase for iBase {
    type DecimalType = i128;

    fn base(&self) -> u16 {
        self.base
    }

    fn digits(&self) -> &Vec<u16> {
        &self.digits
    }

    fn convert(&mut self, base: u16) -> Self {
        let negative = self.digits[0] == 1;
        let mut digits = self.digits.clone();
        digits.remove(0);
        let mut res = utils::convert(self.base, digits, base);

        if negative {
            res.insert(0, 1);
        } else {
            res.insert(0, 0);
        }

        self.digits = res;
        self.base = base;

        self.clone()
    }

    fn from_string(base: u16, number: &str) -> Self {
        let negative = &number[0..1] == "-";
        let digits = if negative {
            let mut digits = from_string(base, &number[1..]);
            digits.insert(0, 1);
            digits
        } else {
            let mut digits = from_string(base, number);
            digits.insert(0, 0);
            digits
        };

        Self { digits, base }
    }

    fn from_vec(base: u16, number: Vec<u16>) -> Self {
        Self {
            digits: number,
            base,
        }
    }

    fn greater_than(&self, number: Self) -> bool {
        let ne_self = self.digits[0] == 1;
        let ne_other = self.digits[0] == 1;

        let numb1 = abs(&self.digits);
        let numb2 = abs(&number.digits);

        if ne_self && !ne_other {
            false
        } else if !ne_self && ne_other {
            true
        } else if !ne_self && !ne_other {
            utils::greater_than(&numb1, &numb2)
        } else if ne_self && ne_other {
            !utils::greater_than(&numb1, &numb2)
        } else {
            unreachable!()
        }
    }

    fn as_binary(&self) -> Self::DecimalType {
        let mut binding_value = self.clone();
        binding_value.convert(2);
        binding_value.display_sub10().unwrap()
    }

    fn as_octal(&self) -> Self::DecimalType {
        let mut binding_value = self.clone();
        binding_value.convert(8);
        binding_value.display_sub10().unwrap()
    }

    fn as_decimal(&self) -> Self::DecimalType {
        let mut binding_value = self.clone();
        binding_value.convert(10);
        binding_value.display_sub10().unwrap()
    }

    fn as_hex(&self) -> String {
        let mut binding_value = self.clone();
        binding_value.convert(16);
        binding_value.display()
    }

    fn display(&self) -> String {
        let negative = self.digits[0] == 1;
        let mut digits = self.digits.clone();
        digits.remove(0);

        let mut res_string = String::new();
        if negative {
            res_string += "-";
        }

        let grapheme_collection: String = digits
            .iter()
            .map(|x| {
                str::from_utf8(
                    GRAPHEMES
                        .get(x)
                        .expect("Internal error. Could not fetch digit from graphemes"),
                )
                .unwrap()
            })
            .collect();

        res_string += &grapheme_collection;

        if res_string.is_empty() || res_string == "-" {
            String::from("0")
        } else {
            res_string.split('\0').collect()
        }
    }
}

impl iBase {
    #[allow(non_snake_case)]
    pub fn as_uBase(&self) -> Option<uBase> {
        if self.digits[0] == 1 {
            None
        } else {
            let mut digits = self.digits.clone();
            digits.remove(0);
            Some(uBase::from_vec(self.base, digits))
        }
    }

    fn display_sub10(&mut self) -> Option<i128> {
        if self.base > 10 {
            return None;
        }

        let mut str = String::new();

        str += &self.display();

        let number: i128 = str.parse().unwrap();
        Some(number)
    }
}

impl Display for iBase {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.display())
    }
}

/// iBase instances can be added together just like regular numbers unsing the '+' operator.
/// Do note however that the resulting iBase instance will be of the same base as the first
/// term. iBase instances of different bases can be added together without issue.
///
/// Example:
///
/// ```rust
///     // create the iBase instances
///     let number1 = iBase::from_string(20, "-1287");
///     assert_eq!(number1.as_decimal(), -8967);
///
///     let number2 = iBase::from_string(15, "1238970");
///     assert_eq!(number2.as_decimal(), 13090380);
///
///     // add the numbers
///     let res = number1 + number2;
///     assert_eq!(res.base(), 20); // because number1 is of base 20, res will also be of base 20
///
///     assert_eq!(res.as_decimal(), -8967 + 13090380);
/// ```
impl Add for iBase {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        let mut rhs = rhs;
        if self.base != rhs.base {
            rhs.convert(self.base);
        }
        let digits = add(self.base, &self.digits, &rhs.digits);
        Self {
            digits,
            base: self.base,
        }
    }
}

/// iBase instances can be subtracted just like regular nubers using the '-' operator.
/// Do note however that the resulting iBase instance will be of the same base as the first
/// term. iBase instances of different bases can be subtracted without issue.
///
/// Do also note that the iBase struct does not support negative numbers, so subtracting a
/// larger number from a smaller one will result in a panic!
///
/// Example:
///
/// ```rust
///
///     // create the iBase instances
///     let number1 = iBase::from_string(20, "1234876");
///     assert_eq!(number1.as_decimal(), 70915346);
///
///     let number2 = iBase::from_string(15, "-3245");
///     assert_eq!(number2.as_decimal(), -10640);
///
///     // subtract the numbers
///     let res = number1 - number2;
///
///     assert_eq!(res.as_decimal(), 70915346 - -10640);
/// ```
impl Sub for iBase {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self::Output {
        let mut rhs = rhs;
        if self.base != rhs.base {
            rhs.convert(self.base);
        }
        let digits = subtract(self.base, &self.digits, &rhs.digits);
        Self {
            digits,
            base: self.base,
        }
    }
}

/// iBase instances can be divided just like normal numbers using the '/' operator.
/// Do note however that the resulting iBase instance will be of the same base as the numerator.
/// iBase instances of different bases can be divided without issue.
///
/// This operation works just like regular integer division; that is, the quotient is rounded down
/// to the nearest whole number.
///
/// Example:
///
/// ```rust
///
///     // create the iBase instances
///     let number1 = iBase::from_string(17, "-AB123");
///     assert_eq!(number1.as_decimal(), -889579);
///
///     let number2 = iBase::from_string(7, "456");
///     assert_eq!(number2.as_decimal(), 237);
///
///     // divide the numbers
///     let res = number1 / number2;
///
///     assert_eq!(res.as_decimal(), -889579 / 237);
/// ```
///
/// Do also note that if the absolute valut of the demomenator is greater than the absolute value of the numerator, the quotient will always be
/// 0 (in whatever base the operation is performed)
///
/// Example:
///
/// ```rust
///     // --- snip ---
///
///     // divide the numbers (|denomenator| is greater than |numerator|)
///     let res = number2 / number1;
///
///     // No matter what base res is, res.display will be "0".
///     // Hence res.as_decimal(), res.as_binary(), res.as_octal() etc. will all be 0.
///     assert_eq!(res.display(), String::from("0"));
/// ```
impl Div for iBase {
    type Output = Self;
    fn div(self, rhs: Self) -> Self::Output {
        let mut rhs = rhs;
        if self.base != rhs.base {
            rhs.convert(self.base);
        }
        let (digits, _) = div(self.base, &self.digits, &rhs.digits);
        Self {
            digits,
            base: self.base,
        }
    }
}

/// iBase instances can be multiplied just like normal numbers using the '*' operator.
/// Do note however that the resulting iBase instance will be of the same base as the first
/// factor. iBase instances of different bases can be multiplied without issue.
///
///
/// Example:
///
/// ```rust
///
///     // create the iBase instances
///     let number1 = iBase::from_string(2, "1001011101101011");
///     assert_eq!(number1.as_decimal(), 38763);
///
///     let number2 = iBase::from_string(27, "-ABGL");
///     assert_eq!(number2.as_decimal(), -205302);
///
///
///     // multiply the numbers
///     let res = number1 * number2;
///
///     assert_eq!(res.as_decimal(), 38763 * -205302);
/// ```
impl Mul for iBase {
    type Output = Self;
    fn mul(self, rhs: Self) -> Self::Output {
        let mut rhs = rhs;
        if self.base != rhs.base {
            rhs.convert(self.base);
        }
        let digits = mul(self.base, &self.digits, &rhs.digits);
        Self {
            digits,
            base: self.base,
        }
    }
}