Functional Weave
Code in Rust

money.convert@1.0.0

impl/rust.rs

2,026 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::math_rational::{multiply_rational, rational, rational_from_value, rational_to_integer};  ← from math.rational ^1.0.0 · built alongside by fune
use super::money_amount::{money, money_from_value, money_to_value, Money};  ← from money.amount ^1.0.0 · built alongside by fune
use super::money_currency_digits::currency_digits;  ← from money.currency-digits ^1.0.0 · built alongside by fune

/// Convert `amount` into the rate's quote currency.
///
/// Exact up to one final rounding into the quote currency's minor unit; the
/// rate is a fraction in major units and each currency's decimal places are
/// looked up rather than assumed to be two.
///
/// # Panics
/// Panics if the amount is not in the rate's base currency, the rate is not
/// positive, a currency has no ISO 4217 minor unit, or the exact value
/// overflows `math.rational`'s range.
pub fn convert_money(amount: &Money, rate: &ExchangeRate, mode: &str) -> Money {
    if amount.currency != rate.base {
        panic!(
            "exchange rate converts {} to {}, not {}",
            rate.base, rate.quote, amount.currency
        );
    }
    let r = rational(rate.rate.numerator, rate.rate.denominator);
    if r.numerator <= 0 {
        panic!("exchange rate must be positive");
    }
    let from_digits = currency_digits(&rate.base) as u32;
    let to_digits = currency_digits(&rate.quote) as u32;

    // minor units of quote per minor unit of base: rate x 10^to_digits / 10^from_digits
    let scale = rational(10_i64.pow(to_digits), 10_i64.pow(from_digits));
    let per_minor = multiply_rational(&r, &scale);
    let exact = multiply_rational(&rational(amount.minor, 1), &per_minor);
    money(rational_to_integer(&exact, mode), &rate.quote)
}

pub fn exchange_rate_from_value(v: &Value) -> ExchangeRate {
    ExchangeRate {
        base: v.get("base").as_str().to_string(),
        quote: v.get("quote").as_str().to_string(),
        rate: rational_from_value(v.get("rate")),
    }
}

pub fn fune_vector(args: &[Value]) -> Value {
    money_to_value(&convert_money(
        &money_from_value(&args[0]),
        &exchange_rate_from_value(&args[1]),
        args[2].as_str(),
    ))
}