use lazy_static::lazy_static;
use onig::*;
lazy_static! {
static ref INVALID_FIRST_CHARACTER: Vec<char> = vec![
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
];
static ref INVALID_CHARACTERS: Regex = Regex::new(
r"(?x)
[\0-\54\56\57\72-\100\133-\136\140\173-\177]
"
).unwrap();
}
pub fn to_radix(
ordinal: &usize,
alphabet: &(Vec<char>, Vec<usize>),
) -> String {
let base: usize = alphabet.0.len();
let subset: usize = base - alphabet.1.len();
let mut carry: usize = 0;
let mut exponent: u8 = 0;
let mut floor: usize = 1;
while *ordinal >= subset * floor + carry {
carry += subset * floor;
exponent += 1;
floor = usize::pow(base, exponent.into());
}
let modulo: usize = (ordinal - carry).wrapping_div(floor);
let mut offset: usize = 0;
for (index, alphabet_position) in alphabet.1.iter().enumerate() {
if modulo + index < *alphabet_position {
break;
}
offset += 1;
}
let mut assigned_index: usize = offset * floor + *ordinal - carry;
let mut encoded_selector = String::new();
for _ in 0..=exponent {
let remainder = assigned_index.rem_euclid(base);
encoded_selector.insert(0, *alphabet.0.get(remainder).unwrap());
assigned_index = (assigned_index - remainder).wrapping_div(base);
}
encoded_selector
}
pub fn into_alphabet_set(alphabet: &str) -> (Vec<char>, Vec<usize>) {
let mut alphabet_set: Vec<char> = Vec::new();
let sanitised_alphabet = INVALID_CHARACTERS.replace_all(alphabet, "");
for char in sanitised_alphabet.chars() {
if !alphabet_set.contains(&char) {
alphabet_set.push(char);
}
}
let invalid_as_first_char_positions: Vec<usize> = alphabet_set
.iter()
.enumerate()
.filter_map(|(index, char)| {
match INVALID_FIRST_CHARACTER.contains(char) {
true => Some(index),
false => None,
}
})
.collect();
(alphabet_set, invalid_as_first_char_positions)
}