use super::funejson::Value; use super::money_amount::{money_from_value, Money}; use super::money_format_data::CURRENCIES; /// Render a monetary amount as text. /// /// Not every currency has two decimal places: yen has none, Kuwaiti dinar has /// three. Dividing by 100 to display an amount is wrong about as often as it /// is right, so the precision comes from the currency table. /// /// # Panics /// Panics if the currency has no entry in the table. pub fn format_money(amount: &Money) -> String { let format = match CURRENCIES.iter().find(|c| c.code == amount.currency) { Some(found) => found, None => panic!( "no formatting rules for currency \"{}\"", amount.currency ), }; let negative = amount.minor < 0; let raw = amount.minor.unsigned_abs().to_string(); let width = (format.digits + 1) as usize; let digits = if raw.len() < width { "0".repeat(width - raw.len()) + &raw } else { raw }; let split = digits.len() - format.digits as usize; let whole = &digits[..split]; let fraction = &digits[split..]; let mut grouped = String::new(); for (i, ch) in whole.chars().enumerate() { if i > 0 && (whole.len() - i) % 3 == 0 { grouped.push_str(format.group_separator); } grouped.push(ch); } let number = if format.digits > 0 { format!("{}{}{}", grouped, format.decimal_separator, fraction) } else { grouped }; let body = if format.symbol_before { format!("{}{}", format.symbol, number) } else { format!("{}{}", number, format.symbol) }; if negative { format!("-{}", body) } else { body } } pub fn fune_vector(args: &[Value]) -> Value { Value::Str(format_money(&money_from_value(&args[0]))) }