///|
let additive_tokens : Array[(Int, String)] = [
(1000, "M"),
(500, "D"),
(100, "C"),
(50, "L"),
(10, "X"),
(5, "V"),
(1, "I"),
]
///|
fn apply_roman_letter_case(text : String, letter_case : LetterCase) -> String {
match letter_case {
Uppercase => text
Lowercase => text.to_lower()
}
}
///|
fn format_additive_upper(value : Int) -> Result[String, FormatError] {
if value < 1 || value > 3999 {
return Err(FormatOutOfRange(value))
}
let mut remaining = value
let mut output = ""
for token in additive_tokens {
while remaining >= token.0 {
output = output + token.1
remaining = remaining - token.0
}
}
Ok(output)
}
///|
fn format_extended_upper(value : Int) -> Result[String, FormatError] {
if value < 1 || value > 3999999 {
return Err(FormatOutOfRange(value))
}
if value <= 3999 {
return format(value)
}
let thousands = value / 1000
let remainder = value % 1000
let group = match format(thousands) {
Ok(text) => text
Err(_) => return Err(FormatOutOfRange(value))
}
let suffix = if remainder == 0 {
""
} else {
match format(remainder) {
Ok(text) => text
Err(_) => return Err(FormatOutOfRange(value))
}
}
Ok("(" + group + ")" + suffix)
}
///|
/// Format one value under an explicit notation mode and letter-case policy.
pub fn format_with_config(
value : Int,
config : FormatConfig,
) -> Result[String, FormatError] {
let upper = match config.mode {
ModernCanonical => format(value)
AdditiveHistorical => format_additive_upper(value)
ClockFace => format_clock_hour(value)
ParenthesizedThousands => format_extended_upper(value)
}
match upper {
Ok(text) => Ok(apply_roman_letter_case(text, config.letter_case))
Err(error) => Err(error)
}
}