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::NumberBase;

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

use super::operations::*;

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

impl NumberBase for uBase {
    type DecimalType = u128;

    // returns a quotient and a remainder in the base of self
    fn base(&self) -> u16 {
        self.base
    }

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

    // done
    fn convert(&mut self, base: u16) -> Self {
        let res = utils::convert(self.base, self.digits.clone(), base);
        self.digits = res;
        self.base = base;

        self.clone()
    }

    // takes a base and ints associated number. Note that the nubmer is a string to account for
    // bases over 10
    fn from_string(base: u16, number: &str) -> Self {
        let digits = from_string(base, number);
        Self { digits, base }
    }

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

    fn greater_than(&self, number: Self) -> bool {
        let mut number = number;
        if self.base != number.base {
            number.convert(self.base);
        }
        greater_than(self.digits(), number.digits())
    }

    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()
    }

    // return a string that corresponds to the number stored in self.digits
    fn display(&self) -> String {
        let mut res_string = String::new();
        let grapheme_collection: String = self
            .digits
            .iter()
            .map(|x| {
                str::from_utf8(
                    GRAPHEMES
                        .get(x)
                        .expect("Internal error. Could not fetch digit form graphemes map"),
                )
                .unwrap()
            })
            .collect();

        res_string += &grapheme_collection;

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

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

impl uBase {
    // Commonly used bases as a shorthand
    fn display_sub10(&mut self) -> Option<u128> {
        if self.base > 10 {
            return None;
        }

        let str: String = self.display();

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

/// uBase instances can be added together just like regular numbers unsing the '+' operator.
/// Do note however that the resulting uBase instance will be of the same base as the first
/// term. uBase instances of different bases can be added together without issue.
///
/// Example:
///
/// ```rust
///     // create the uBase instances
///     let number1 = uBase::from_string(20, "1287");
///     assert_eq!(number1.as_decimal(), 8967);
///
///     let number2 = uBase::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 uBase {
    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,
        }
    }
}

/// uBase instances can be subtracted just like regular nubers using the '-' operator.
/// Do note however that the resulting uBase instance will be of the same base as the first
/// term. uBase instances of different bases can be subtracted without issue.
///
/// Do also note that the uBase struct does not support negative numbers, so subtracting a
/// larger number from a smaller one will result in a panic!
///
/// Example:
///
/// ```rust
///
///     // create the uBase instances
///     let number1 = uBase::from_string(20, "1234876");
///     assert_eq!(number1.as_decimal(), 70915346);
///
///     let number2 = uBase::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 uBase {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        let mut rhs = rhs;
        if self.base != rhs.base {
            rhs.convert(self.base);
        }

        if !self.greater_than(rhs.clone()) {
            panic!("Attempted to subtract with overflow");
        }

        let digits = subtract(self.base, self.digits(), rhs.digits());

        Self {
            digits,
            base: self.base,
        }
    }
}

/// uBase instances can be divided just like normal numbers using the '/' operator.
/// Do note however that the resulting uBase instance will be of the same base as the numerator.
/// uBase 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 uBase instances
///     let number1 = uBase::from_string(17, "AB123");
///     assert_eq!(number1.as_decimal(), 889579);
///
///     let number2 = uBase::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 demomenator is greater than 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 the 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 uBase {
    type Output = Self;

    fn div(self, rhs: Self) -> Self::Output {
        let mut rhs = rhs;
        if self.base != rhs.base {
            rhs.convert(self.base);
        }

        let (quotient, _) = div(self.base, self.digits(), rhs.digits());

        Self {
            digits: quotient,
            base: self.base,
        }
    }
}

/// uBase instances can be multiplied just like normal numbers using the '*' operator.
/// Do note however that the resulting uBase instance will be of the same base as the first
/// factor. uBase instances of different bases can be multiplied without issue.
///
///
/// Example:
///
/// ```rust
///
///     // create the uBase instances
///     let number1 = uBase::from_string(2, "1001011101101011");
///     assert_eq!(number1.as_decimal(), 38763);
///
///     let number2 = uBase::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 uBase {
    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,
        }
    }
}