Functional Weave
Code in Python

money.amount@1.0.0

impl/rust.rs

1,599 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

fn is_currency_code(code: &str) -> bool {
    code.len() == 3 && code.chars().all(|c| c.is_ascii_uppercase())
}

/// # Panics
/// Panics if `currency` is not an uppercase ISO 4217 alphabetic code.
pub fn money(minor: i64, currency: &str) -> Money {
    if !is_currency_code(currency) {
        panic!("\"{}\" is not an uppercase ISO 4217 currency code", currency);
    }
    Money {
        minor,
        currency: currency.to_string(),
    }
}

/// Guard against the silent nonsense of adding GBP to EUR.
///
/// # Panics
/// Panics if the two amounts are in different currencies.
pub fn assert_same_currency(a: &Money, b: &Money) {
    if a.currency != b.currency {
        panic!("currency mismatch: {} and {}", a.currency, b.currency);
    }
}

pub fn zero(currency: &str) -> Money {
    money(0, currency)
}

pub fn money_to_value(m: &Money) -> Value {
    Value::obj(vec![
        ("minor", Value::Int(m.minor)),
        ("currency", Value::str(&m.currency)),
    ])
}

pub fn money_from_value(v: &Value) -> Money {
    Money {
        minor: v.get("minor").as_i64(),
        currency: v.get("currency").as_str().to_string(),
    }
}

pub fn fune_vector(args: &[Value]) -> Value {
    // Refuse what the typed signature cannot hold, with the wording TypeScript
    // and Python use, rather than let the conversion below quietly change it.
    if let Value::Float(f) = args[0] {
        if f.fract() != 0.0 {
            panic!("money() takes integer minor units, received {}", f);
        }
    }
    money_to_value(&money(args[0].as_i64(), args[1].as_str()))
}