use std::collections::HashMap;
use crate::util::unique;
use crate::BaseCustom;
use std::ops::Range;
use std::fmt;
impl BaseCustom<char> {
pub fn new(chars: Vec<char>) -> BaseCustom<char> {
if chars.iter().count() < 2 { panic!("Too few numeric units! Provide two or more.") }
if chars.iter().count() > 255 { panic!("Too many numeric units!") }
let chars = unique(chars);
let mut mapped = HashMap::with_capacity(chars.iter().count());
for (i,c) in chars.iter().enumerate() {
mapped.insert(c.clone(), i as u8);
}
BaseCustom::<char> {
primitives: chars.clone(),
primitives_hash: mapped,
base: chars.iter().count() as u64,
delim: None,
}
}
pub fn gen(&self, input_val: u64) -> String {
if input_val == 0 {
return format!("{}", self.primitives[0]);
}
let mut number = input_val;
let mut result = String::new();
loop {
if number == 0 { break };
result.insert(0, self.primitives[(number % self.base) as usize]);
number = number/self.base;
};
format!("{}", result)
}
pub fn char(&self, input_val: usize) -> Option<char> {
if input_val > self.primitives.len() { return None }
Some(self.primitives[input_val])
}
pub fn decimal<S>(&self, input_val: S) -> u64
where S: Into<String> {
let input_val = input_val.into();
input_val.chars().rev().enumerate().fold(0, |sum, (i, chr)|
sum + (self.primitives_hash[&chr] as u64) * self.base.pow(i as u32)
)
}
pub fn zero(&self) -> &char {
&self.primitives[0]
}
pub fn one(&self) -> &char {
&self.primitives[1]
}
pub fn nth(&self, pos: usize) -> Option<&char> {
if pos < self.base as usize {
Some(&self.primitives[pos])
} else {
None
}
}
pub fn from_ordinal_range(range: Range<u32>) -> BaseCustom<char> {
let min = std::cmp::max(32, range.start);
let max = std::cmp::min(127, range.end);
let mut chars: Vec<char> = Vec::with_capacity(std::cmp::min(range.len(), 95));
for chr in min..max {
chars.push(std::char::from_u32(chr).unwrap());
}
BaseCustom::<char>::new(chars)
}
}
impl PartialEq for BaseCustom<char> {
fn eq(&self, other: &BaseCustom<char>) -> bool {
self.primitives == other.primitives &&
self.base == other.base &&
self.delim == other.delim
}
}
impl fmt::Debug for BaseCustom<char> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"BaseCustom\n\tprimitives: {:?}\n\tprimitives_hash: {:?}\n\tbase: {}\n\tdelim: {:?}",
self.primitives, self.primitives_hash, self.base, self.delim
)
}
}