use super::funejson::Value; use super::money_amount::{money, money_from_value, money_to_value, Money}; /// 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 { 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(), ) }