number-based 0.2.3

number-based is an attempt of mine to make working with number bases simple.
Documentation
use crate::graphemes::grapheme_creation::GRAPHEMES;

pub fn vec_to_arr<T, const N: usize>(v: Vec<T>) -> [T; N] {
    v.try_into()
        .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
}

pub fn from_string(base: u16, number: &str) -> Vec<u16> {
    if base > GRAPHEMES.len() as u16 {
        panic!("There are not enough graphemes create number. Use a lower base");
    }
    // digits is the vector that will be returned in the uBase instance
    let number = number.trim();
    let digits: Vec<u16> = number
        .split("")
        .filter(|s| s != &"")
        .map(|s| {
            let byte_arr = s.as_bytes();
            let mut byte_vec: Vec<u8> = Vec::new();
            // the byte array must match [u8; 4], so we fill the rest of the array with zeros
            byte_vec.resize(4 - byte_arr.len(), 0);
            // fill the array, ending up with a Vec<u8> of length 4
            for byte in byte_arr {
                byte_vec.push(*byte);
            }

            let comp_arr = &vec_to_arr(byte_vec);

            // find the associated key to the grapheme provided in the string
            if let Some(key) =
                GRAPHEMES
                    .iter()
                    .find_map(|(key, val)| if val == comp_arr { Some(key) } else { None })
            {
                if *key > base - 1 {
                    let error = String::from("value ")
                        + number
                        + "  contains graphemes greater than number base "
                        + &base.to_string();
                    panic!("{error}");
                }
                *key
            } else {
                let error = String::from("value ") + number + " not in valid graphemes";
                panic!("{error}");
            }
        })
        .collect();

    digits
}

pub fn add(base: u16, numb1: &[u16], numb2: &[u16]) -> Vec<u16> {
    let mut numb1 = numb1.to_owned();
    numb1.reverse();
    let mut numb2 = numb2.to_owned();
    numb2.reverse();

    let mut res: Vec<u16> = Vec::new();

    let (greatest, smallest) = if numb1.len() > numb2.len() {
        (&numb1, &numb2)
    } else {
        (&numb2, &numb1)
    };

    for i in 0..smallest.len() {
        res.push(greatest[i] + smallest[i]);
    }
    for digit in greatest.iter().skip(smallest.len()) {
        res.push(*digit);
    }

    for i in 0..res.len() {
        if res[i] >= base {
            // means we need to add another digit
            if i == res.len() - 1 {
                res.push(1);
            } else {
                res[i + 1] += 1;
            }
            res[i] -= base;
        }
    }

    res.reverse();
    res
}

/// sebtraction will assume that numb1 >= numb2
pub fn subtract(base: u16, numb1: &[u16], numb2: &[u16]) -> Vec<u16> {
    let mut numb1 = numb1.to_owned();
    numb1.reverse();
    let mut numb2 = numb2.to_owned();
    numb2.reverse();

    let mut res: Vec<i32> = Vec::new();

    for i in 0..numb2.len() {
        res.push(numb1[i] as i32 - numb2[i] as i32);
    }
    for digit in numb1.iter().skip(numb2.len()) {
        res.push(*digit as i32);
    }

    for i in 0..res.len() {
        if res[i] < 0 {
            res[i + 1] -= 1;
            res[i] += base as i32;
        }
    }

    while res.last() == Some(&0_i32) {
        res.pop();
    }

    res.reverse();

    res.iter().map(|x| x.to_owned() as u16).collect()
}

pub fn trim_base_vec(vec: &mut Vec<u16>) -> Vec<u16> {
    vec.reverse();
    while vec.last() == Some(&0_u16) {
        vec.pop();
    }
    vec.reverse();
    vec.to_owned()
}

pub fn greater_than(numb1: &[u16], numb2: &[u16]) -> bool {
    let numb1 = trim_base_vec(&mut numb1.to_owned());
    let numb2 = trim_base_vec(&mut numb2.to_owned());
    if numb1.len() > numb2.len() {
        return true;
    } else if numb1.len() == numb2.len() {
        for i in 0..numb1.len() {
            if numb1[i] > numb2[i] {
                return true;
            } else if numb2[i] > numb1[i] {
                return false;
            }
        }
        false
    } else {
        false
    }
}

fn convert_base10(base: u16, numb: &[u16]) -> u128 {
    let mut numb = numb.to_owned();
    numb.reverse();
    let mut res: u128 = 0;
    for i in 0..numb.len() {
        res += numb[i as usize] as u128 * (base as u128).pow(i as u32) as u128;
    }
    res
}

pub fn div(base: u16, numb1: &[u16], numb2: &[u16]) -> (Vec<u16>, Vec<u16>) {
    let mut numb1 = numb1.to_owned();
    let mut numb2 = numb2.to_owned();

    // prepare the numbers
    trim_base_vec(&mut numb1);
    trim_base_vec(&mut numb2);

    // if the divisor is greater than the divident, there is no reason to perform a comprehensive
    // calculation, we can simply return 0 as the quotient and the divident as the remainder
    if greater_than(&numb2, &numb1) {
        return (vec![0], numb1);
    }

    let mut quo: Vec<u16> = Vec::new();
    let mut divident: Vec<u16> = Vec::new();
    for numb in &numb1 {
        divident.push(*numb);
        if greater_than(&numb2, &divident) {
            quo.push(0);
        } else {
            // note that here, the numbers are of the same length
            // convert numbers to base 10
            let divident_base10 = convert_base10(base, &divident);
            let divisor_base10 = convert_base10(base, &numb2);
            let res = (divident_base10 / divisor_base10) as u16;
            quo.push(res);

            // prepare divident for next iteration
            divident = subtract(base, &divident, &mul(base, &vec![res], &numb2));
        }
    }

    let remainder = trim_base_vec(&mut subtract(base, &numb1, &mul(base, &quo, &numb2)));

    (quo, remainder)
}

pub fn mul(base: u16, number1: &[u16], number2: &[u16]) -> Vec<u16> {
    let numb1 = if greater_than(number1, number2) {
        let mut numb1 = number1.to_owned();
        numb1.reverse();
        numb1
    } else {
        let mut numb2 = number2.to_owned();
        numb2.reverse();
        numb2
    };

    let numb2 = if !greater_than(number1, number2) {
        let mut numb1 = number1.to_owned();
        numb1.reverse();
        numb1
    } else {
        let mut numb2 = number2.to_owned();
        numb2.reverse();
        numb2
    };

    let mut mul_pieces: Vec<Vec<u16>> = Vec::new();

    for digit2 in numb2 {
        let mut mul_piece: Vec<u16> = Vec::new();
        let mut waiting_value: u16 = 0;
        let mut placing_value: u16;
        for digit1 in &numb1 {
            let product = digit1 * digit2;
            placing_value = waiting_value + (product - (product / base) * base);
            waiting_value = product / base;

            if placing_value >= base {
                placing_value -= base;
                waiting_value += 1;
            }
            mul_piece.push(placing_value);
        }
        if waiting_value != 0 {
            mul_piece.push(waiting_value);
        }
        mul_piece.reverse();
        mul_pieces.push(mul_piece);
    }

    for (i, piece) in mul_pieces.iter_mut().enumerate() {
        for _ in 0..i {
            piece.push(0);
        }
    }

    let mut res: Vec<u16> = vec![];
    for piece in mul_pieces {
        res = add(base, &res, &piece);
    }

    trim_base_vec(&mut res)
}

fn as_base10(base: u16, mut numb: Vec<u16>) -> u16 {
    let mut res: u128 = 0;
    numb.reverse();

    for (i, digit) in numb.iter().enumerate() {
        res += *digit as u128 * (base as u128).pow(i as u32);
    }

    res as u16
}

fn from_base10(base: u16, mut numb: u16) -> Vec<u16> {
    let mut res: Vec<u16> = Vec::new();
    while numb > 0 {
        res.push(numb % base);
        numb /= base;
    }

    res.reverse();
    res
}

pub fn convert(self_base: u16, self_digits: Vec<u16>, base: u16) -> Vec<u16> {
    if base > GRAPHEMES.len() as u16 {
        panic!("Cannot convert. Requested base is greater than number of graphemes.");
    }
    // convert input base to self.base so that we can perform division in self.base
    let mut base_as_self = from_base10(self_base, base);

    let mut res: Vec<u16> = Vec::new();

    let mut numb = self_digits;
    while greater_than(&numb, &base_as_self)
        || trim_base_vec(&mut numb) == trim_base_vec(&mut base_as_self)
    {
        let (quotient, rem) = div(self_base, &numb, &base_as_self);
        numb = quotient;
        res.push(as_base10(self_base, rem));
    }
    res.push(as_base10(self_base, numb));

    res.reverse();
    res
}