Functional Weave
Code in TypeScript

money.format@1.0.0

impl/rust.rs

1,843 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::money_amount::{money_from_value, Money};  ← from money.amount ^1.0.0 · built alongside by fune
use super::money_format_data::CURRENCIES;  ← this capability’s own data, compiled from data/currencies.json into the same file by fune build

/// 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])))
}