use phf::phf_map;
static ROMAN_DIGITS: phf::Map<u8, usize> = phf_map! {
b'i' => 1,
b'v' => 5,
b'x' => 10,
b'l' => 50,
b'c' => 100,
b'd' => 500,
b'm' => 1000,
};
pub(crate) fn _roman_to_number(text: &str) -> Option<usize> {
let mut total = 0;
let mut prev_digit = 0;
for byte in text.to_lowercase().bytes().rev() {
match ROMAN_DIGITS.get(&byte) {
Some(&n) => {
if n < prev_digit {
total -= n;
} else {
total += n;
}
prev_digit = n;
}
None => return None,
}
}
Some(total)
}
#[inline]
pub(crate) fn is_roman(c: u8) -> bool {
matches!(
c.to_ascii_lowercase(),
b'i' | b'v' | b'x' | b'l' | b'c' | b'd' | b'm'
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_roman_numerals() {
let examples = vec![
("MMXXII", Some(2022)),
("ix", Some(9)),
("wrong", None),
("McmXiI", Some(1912)),
];
for (example, want) in examples {
let got = roman_to_number(example);
assert_eq!(want, got);
}
}
}