use crate::map;
use std::fmt;
use std::fmt::Formatter as Fmt;
use std::fmt::Result;
use std::fmt::Write;
pub fn shortscale_display(num: u64) -> String {
let mut s = String::new();
write!(&mut s, "{}", NumWords::new(num)).unwrap();
return s;
}
#[derive(Debug)]
pub struct NumWords {
n: u64,
}
impl NumWords {
pub fn new(n: u64) -> Self {
Self { n }
}
fn display(&self, f: &mut Fmt<'_>) -> Result {
if self.n <= 20 || self.n > 999_999_999_999_999_999 {
return write!(f, "{}", map(self.n));
}
let mut len: usize = 0;
self.scale(f, &mut len, 1_000_000_000_000_000)?;
self.scale(f, &mut len, 1_000_000_000_000)?;
self.scale(f, &mut len, 1_000_000_000)?;
self.scale(f, &mut len, 1_000_000)?;
self.scale(f, &mut len, 1_000)?;
self.hundreds(f, self.n, &mut len)?;
self.tens_and_units(f, self.n, len > 0, &mut len)?;
Ok(())
}
fn tens_and_units(&self, f: &mut Fmt<'_>, num: u64, and_word: bool, len: &mut usize) -> Result {
let num = num % 100;
if num == 0 {
return Ok(());
}
if and_word {
self.write_word(f, "and", len)?;
};
match num {
1..=20 => self.write_word(f, map(num), len)?,
_ => {
self.write_word(f, map(num / 10 * 10), len)?;
let num = num % 10;
match num {
0 => (),
_ => self.write_word(f, map(num), len)?,
}
}
}
Ok(())
}
fn hundreds(&self, f: &mut Fmt<'_>, num: u64, len: &mut usize) -> Result {
let num = num / 100 % 10;
if num == 0 {
return Ok(());
}
self.write_word(f, map(num), len)?;
self.write_word(f, map(100), len)?;
Ok(())
}
fn scale(&self, f: &mut Fmt<'_>, len: &mut usize, thousands: u64) -> Result {
let num = self.n / thousands % 1_000;
if num == 0 {
return Ok(());
}
self.hundreds(f, num, len)?;
let and_word: bool = (num / 100 % 10) > 0;
self.tens_and_units(f, num, and_word, len)?;
self.write_word(f, map(thousands), len)?;
Ok(())
}
fn write_word(&self, f: &mut Fmt<'_>, word: &str, len: &mut usize) -> Result {
if *len > 0 {
f.write_str(" ")?;
*len += " ".len();
}
f.write_str(word)?;
*len += word.len();
Ok(())
}
}
impl fmt::Display for NumWords {
fn fmt(&self, f: &mut Fmt<'_>) -> Result {
self.display(f)
}
}
pub fn shortscale_str_push(num: u64) -> String {
if num <= 20 || num > 999_999_999_999_999_999 {
return String::from(map(num));
}
let mut s = String::new();
push_scale(&mut s, num, 1_000_000_000_000_000);
push_scale(&mut s, num, 1_000_000_000_000);
push_scale(&mut s, num, 1_000_000_000);
push_scale(&mut s, num, 1_000_000);
push_scale(&mut s, num, 1_000);
push_hundreds(&mut s, num);
let and_word: bool = s.len() > 0;
push_tens_and_units(&mut s, num, and_word);
return s;
}
fn push_word(s: &mut String, word: &str) {
if s.len() > 0 {
s.push_str(" ");
}
s.push_str(word);
}
fn push_tens_and_units(s: &mut String, num: u64, and_word: bool) {
let num = num % 100;
if num == 0 {
return;
}
if and_word {
push_word(s, "and");
}
match num {
1..=20 => push_word(s, map(num)),
_ => {
push_word(s, map(num / 10 * 10));
let num = num % 10;
match num {
0 => (),
_ => push_word(s, map(num)),
};
}
};
}
fn push_hundreds(s: &mut String, num: u64) {
let num = num / 100 % 10;
if num == 0 {
return;
}
push_word(s, map(num));
push_word(s, map(100))
}
fn push_scale(s: &mut String, num: u64, thousands: u64) {
let num = num / thousands % 1_000;
if num == 0 {
return;
}
push_hundreds(s, num);
let and_word: bool = (num / 100 % 10) > 0;
push_tens_and_units(s, num, and_word);
push_word(s, map(thousands));
}
type Strvec = Vec<&'static str>;
pub fn shortscale_vec_push(num: u64) -> String {
if num <= 20 || num > 999_999_999_999_999_999 {
return String::from(map(num));
}
let mut v: Strvec = Vec::new();
vec_push_scale(&mut v, num, 1_000_000_000_000_000);
vec_push_scale(&mut v, num, 1_000_000_000_000);
vec_push_scale(&mut v, num, 1_000_000_000);
vec_push_scale(&mut v, num, 1_000_000);
vec_push_scale(&mut v, num, 1_000);
vec_push_hundreds(&mut v, num);
let and_word: bool = v.len() > 0;
vec_push_tens_and_units(&mut v, num, and_word);
return v.join(" ");
}
fn vec_push_tens_and_units(v: &mut Strvec, num: u64, and_word: bool) {
let num = num % 100;
if num == 0 {
return;
}
if and_word {
v.push("and");
}
match num {
1..=20 => v.push(map(num)),
_ => {
v.push(map(num / 10 * 10));
let num = num % 10;
match num {
0 => (),
_ => v.push(map(num)),
};
}
};
}
fn vec_push_hundreds(v: &mut Strvec, num: u64) {
let num = num / 100 % 10;
if num == 0 {
return;
}
v.push(map(num));
v.push(map(100))
}
fn vec_push_scale(v: &mut Strvec, num: u64, thousands: u64) {
let num = num / thousands % 1_000;
if num == 0 {
return;
}
vec_push_hundreds(v, num);
let and_word: bool = (num / 100 % 10) > 0;
vec_push_tens_and_units(v, num, and_word);
v.push(map(thousands));
}
pub fn shortscale_vec_concat(num: u64) -> String {
if num <= 20 || num > 999_999_999_999_999_999 {
return String::from(map(num));
}
let vec = [
scale(num, 1_000_000_000_000_000),
scale(num, 1_000_000_000_000),
scale(num, 1_000_000_000),
scale(num, 1_000_000),
scale(num, 1_000),
hundreds(num),
]
.concat();
let vec = concat_and(vec, tens_and_units(num));
vec.join(" ")
}
fn lookup(num: u64) -> Strvec {
match num {
0 => vec![],
_ => vec![map(num)],
}
}
fn tens_and_units(num: u64) -> Strvec {
let num = num % 100;
match num {
0..=20 => lookup(num),
_ => [lookup(num / 10 * 10), lookup(num % 10)].concat(),
}
}
fn hundreds(num: u64) -> Strvec {
let num = num / 100 % 10;
match num {
0 => vec![],
_ => [lookup(num), lookup(100)].concat(),
}
}
fn scale(num: u64, thousands: u64) -> Strvec {
let num = num / thousands % 1_000;
match num {
0 => vec![],
_ => [one_to_999(num), lookup(thousands)].concat(),
}
}
fn one_to_999(num: u64) -> Strvec {
concat_and(hundreds(num), tens_and_units(num))
}
fn concat_and(v1: Strvec, v2: Strvec) -> Strvec {
match (v1.len(), v2.len()) {
(_, 0) => v1,
(0, _) => v2,
(_, _) => [v1, vec!["and"], v2].concat(),
}
}
pub fn shortscale_string_join(num: u64) -> String {
if num <= 20 || num > 999_999_999_999_999_999 {
return String::from(map(num));
}
let mut s = String::new();
join_words(&mut s, " ", scale_words(num, 1_000_000_000_000_000));
join_words(&mut s, " ", scale_words(num, 1_000_000_000_000));
join_words(&mut s, " ", scale_words(num, 1_000_000_000));
join_words(&mut s, " ", scale_words(num, 1_000_000));
join_words(&mut s, " ", scale_words(num, 1_000));
join_words(&mut s, " ", hundreds_words(num));
join_words(&mut s, " and ", tens_and_units_words(num));
s
}
fn join_words(s: &mut String, sep: &str, words: String) {
match (s.len(), words.len()) {
(_, 0) => (),
(0, _) => s.push_str(&words),
(_, _) => {
s.push_str(sep);
s.push_str(&words);
}
}
}
fn lookup_word(num: u64) -> String {
match num {
0 => String::from(""),
_ => String::from(map(num)),
}
}
fn tens_and_units_words(num: u64) -> String {
let num = num % 100;
let tens = num / 10 * 10;
let units = num % 10;
match (tens, units) {
(0, _) => lookup_word(units),
(10, _) => lookup_word(num),
(_, 0) => lookup_word(tens),
(_, _) => [lookup_word(tens), String::from(" "), lookup_word(units)].concat(),
}
}
fn hundreds_words(num: u64) -> String {
let num = num / 100 % 10;
match num {
0 => lookup_word(num),
_ => [lookup_word(num), String::from(" "), lookup_word(100)].concat(),
}
}
fn scale_words(num: u64, thousands: u64) -> String {
let num = num / thousands % 1_000;
match num {
0 => lookup_word(num),
_ => [
one_to_999_words(num),
String::from(" "),
lookup_word(thousands),
]
.concat(),
}
}
fn one_to_999_words(num: u64) -> String {
let h = hundreds_words(num);
let tu = tens_and_units_words(num);
match (h.len(), tu.len()) {
(0, _) => tu,
(_, 0) => h,
(_, _) => [h, String::from(" and "), tu].concat(),
}
}