Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use std::collections::HashSet;
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::dates_add_days::{epoch_day_from_iso, iso_from_epoch_day}; ← from dates.add-days ^1.0.0 · built alongside by fune
use super::dates_day_of_week::day_of_week; ← from dates.day-of-week ^1.0.0 · built alongside by fune
/// The `days`-th working day after `iso` (before it when negative), skipping
/// Saturdays, Sundays and the listed holidays. The start date is never counted,
/// so Friday + 1 and Saturday + 1 are both Monday, as in spreadsheet WORKDAY.
/// Zero returns `iso` unchanged.
///
/// # Panics
/// Panics if the date or any holiday is malformed or impossible, or the result
/// leaves 0001-9999.
pub fn add_business_days(iso: &str, days: i64, holidays: &[String]) -> String {
let mut day = epoch_day_from_iso(iso);
// Every holiday is validated even when the move never reaches it, so a typo
// in a calendar fails on the next run rather than in the year it matters.
let excluded: HashSet<i64> = holidays.iter().map(|h| epoch_day_from_iso(h)).collect();
let step: i64 = if days < 0 { -1 } else { 1 };
let mut weekday = day_of_week(iso);
let mut remaining = days.abs();
while remaining > 0 {
day += step;
weekday = (weekday - 1 + step).rem_euclid(7) + 1;
if weekday <= 5 && !excluded.contains(&day) {
remaining -= 1;
}
}
iso_from_epoch_day(day)
}
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!("days must be an integer, received {}", f);
}
}
let holidays: Vec<String> = args[2].as_arr().iter().map(|v| v.as_str().to_string()).collect();
Value::str(&add_business_days(args[0].as_str(), args[1].as_i64(), &holidays))
}