russian_numbers 0.2.0

crate for converting numbers into names in Russian language
Documentation
// hs - hundreds
// ds - dozens
// us - units

pub(crate) const ZERO: &str = "ноль";

#[inline]
pub(crate) const fn ds1us2str(us: u8) -> &'static str {
    match us {
        0 => "десять",
        1 => "одиннадцать",
        2 => "двенадцать",
        3 => "тринадцать",
        4 => "четырнадцать",
        5 => "пятнадцать",
        6 => "шестнадцать",
        7 => "семнадцать",
        8 => "восемнадцать",
        9 => "девятнадцать",
        _ => unreachable!(),
    }
}

#[inline]
pub(crate) const fn ds2str(ds: u8) -> &'static str {
    match ds {
        1 => unreachable!(), // ts1ds_to_str
        2 => "двадцать",
        3 => "тридцать",
        4 => "сорок",
        5 => "пятьдесят",
        6 => "шестьдесят",
        7 => "семьдесят",
        8 => "восемьдесят",
        9 => "девяносто",
        _ => unreachable!(),
    }
}

#[inline]
pub(crate) const fn hs2str(hs: u8) -> &'static str {
    match hs {
        1 => "сто",
        2 => "двести",
        3 => "триста",
        4 => "четыреста",
        5 => "пятьсот",
        6 => "шестьсот",
        7 => "семьсот",
        8 => "восемьсот",
        9 => "девятьсот",
        _ => unreachable!(),
    }
}

#[inline]
pub(crate) const fn us2str(us: u8, fem: bool) -> &'static str {
    match us {
        1 => {
            if fem {
                "одна"
            } else {
                "один"
            }
        }
        2 => {
            if fem {
                "две"
            } else {
                "два"
            }
        }
        3 => "три",
        4 => "четыре",
        5 => "пять",
        6 => "шесть",
        7 => "семь",
        8 => "восемь",
        9 => "девять",
        _ => unreachable!(),
    }
}

macro_rules! translate {
    ($name:ident, 1: $one:literal, 2..=4: $sec:literal, _: $any:literal) => {
        pub(crate) const fn $name([ds, us]: [u8; 2]) -> &'static str {
            const ANY: &str = $any;
            if ds == 1 { ANY } else {
                match us {
                    1 => $one,
                    2..=4 => $sec,
                    _ => ANY,
                }
            }
        }
    };
    ($($name:ident: $num:literal, 1: $one:literal, 2..=4: $sec:literal, _: $any:literal);+) => {
        $(translate!($name, 1: $one, 2..=4: $sec, _: $any);)+
        /// pos = log10(num) / 3
        ///
        /// [src](https://chemister.ru/Other/Text/bignumber.htm)
        pub(crate) const fn grade(pos: u32) -> Option<fn([u8; 2]) -> &'static str> {
            match pos {
                $($num => Some($name),)+
                _ => None
            }
        }
    }
}

translate!(
    thousand: 1, 1: "тысяча", 2..=4: "тысячи", _: "тысяч";
    million: 2, 1: "миллион", 2..=4: "миллиона", _: "миллионов";
    milliard: 3, 1: "миллиард", 2..=4: "миллиарда", _: "миллиардов";
    trillion: 4, 1: "триллион", 2..=4: "триллиона", _: "триллионов";
    kvadrillion: 5, 1: "квадриллион", 2..=4: "квадриллиона", _: "квадриллиов";
    kvintillion: 6, 1: "квинтиллион", 2..=4: "квинтиллиона", _: "квинтиллионов";
    sextillion: 7, 1: "секстиллион", 2..=4: "секстиллиона", _: "секстиллионов";
    septillion: 8, 1: "септиллион", 2..=4: "септиллиона", _: "септиллионов";
    octillion: 9, 1: "октиллион", 2..=4: "октиллиона", _: "октиллионов";
    nonilion: 10, 1: "нониллион", 2..=4: "нониллиона", _: "нониллионов";
    decilion: 11, 1: "дециллион", 2..=4: "дециллиона", _: "дециллионов";
    andecillion: 12, 1: "анцедиллион", 2..=4: "анцедиллион", _: "анцедиллионов";
    duodecim: 13, 1: "дуодециллион", 2..=4: "дуодециллиона", _: "дуодециллионов";
    tredecim: 14, 1: "тредециллион", 2..=4: "тредециллиона", _: "тредециллионов";
    quattordecillion: 15, 1: "кваттордециллион", 2..=4: "кваттордециллиона", _: "кваттордециллионов";
    quindecim: 16, 1: "квиндециллион", 2..=4: "квиндециллиона", _: "квиндециллионов";
    sedecim: 17, 1: "сексдециллион", 2..=4: "сексдециллиона", _: "сексдециллионов";
    septendecin: 18, 1: "септемдециллион", 2..=4: "септемдециллиона", _: "септемдециллионов";
    octodecin: 19, 1: "октодециллион", 2..=4: "октодециллиона", _: "октодециллионов";
    novemdecin: 20, 1: "новемдециллион", 2..=4: "новемдециллиона", _: "новемдециллионов";
    viginti: 21, 1: "вигинтиллион", 2..=4: "вигинтиллиона", _: "вигинтиллионов";
    anviginti: 22, 1: "анвигинтиллион", 2..=4: "анвигинтиллиона", _: "анвигинтиллионов";
    duoviginti: 23, 1: "дуовигинтиллион", 2..=4: "дуовигинтиллиона", _: "дуовигинтиллионов";
    treviginti: 24, 1: "тревигинтиллион", 2..=4: "тревигинтиллиона", _: "тревигинтиллионов";
    quattroviginti: 25, 1: "кватторвигинтиллион", 2..=4: "кватторвигинтиллиона", _: "кватторвигинтиллионов";
    quinviginti: 26, 1: "квинвигинтиллион", 2..=4: "квинвигинтиллиона", _: "квинвигинтиллионов";
    sexviginti: 27, 1: "сексвигинтиллион", 2..=4: "сексвигинтиллиона", _: "сексвигинтиллионов";
    septviginti: 28, 1: "септемвигинтиллион", 2..=4: "септемвигинтиллиона", _: "септемвигинтиллионов";
    octoviginti: 29, 1: "октовигинтиллион", 2..=4: "октовигинтиллиона", _: "октовигинтиллионов";
    novemviginti: 30, 1: "новемвигинтиллион", 2..=4: "новемвигинтиллиона", _: "новемвигинтиллионов";
    triginti: 31, 1: "тригинтиллион", 2..=4: "тригинтиллиона", _: "тригинтиллионов";
    antriginti: 32, 1: "антригинтиллион", 2..=4: "антригинтиллиона", _: "антригинтиллионов"
    // : , 1: "", 2..=4: "", _: "";
);