Functional Weave
Code in Python

money.split-even@1.0.0

impl/rust.rs

1,510 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, money_from_value, money_to_value, Money};  ← from money.amount ^1.0.0 · built alongside by fune

/// Split `amount` into `parts` near-equal shares that sum to exactly `amount`.
///
/// The leftover minor units go one each to the first shares, and a negative
/// amount splits as the mirror image of the positive one, so a refund undoes
/// the original split share for share.
///
/// # Panics
/// Panics if `parts` is less than 1.
pub fn split_even(amount: &Money, parts: i64) -> Vec<Money> {
    if parts < 1 {
        panic!("parts must be at least 1, received {}", parts);
    }
    let sign = if amount.minor < 0 { -1 } else { 1 };
    let magnitude = amount.minor.unsigned_abs() as i128;
    let base = magnitude / parts as i128;
    let leftover = magnitude % parts as i128;
    (0..parts as i128)
        .map(|i| {
            let share = base + if i < leftover { 1 } else { 0 };
            money(sign * share as i64, &amount.currency)
        })
        .collect()
}

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[1] {
        if f.fract() != 0.0 {
            panic!("parts must be a whole number, received {}", f);
        }
    }
    Value::Arr(
        split_even(&money_from_value(&args[0]), args[1].as_i64())
            .iter()
            .map(money_to_value)
            .collect(),
    )
}