Functional Weave
Code in Python

health.waiting-time@1.0.1

impl/rust.rs

2,400 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::dates_add_days::{add_days, days_between, parse_iso_date};  ← from dates.add-days ^1.0.0 · built alongside by fune

/// 18 weeks: a wait of exactly 126 days is still within the standard.
const EIGHTEEN_WEEKS_DAYS: i64 = 126;

/// The length of a referral-to-treatment pathway, counted from the clock start
/// to the clock stop, or to `on_date` while the patient is still waiting.
/// There are no pauses: NHS England removed them in 2015.
///
/// # Panics
/// Panics on a malformed date, `on_date` or `clock_stop` before `clock_start`,
/// or `clock_stop` after `on_date`.
pub fn rtt_waiting_time(clock_start: &str, clock_stop: Option<&str>, on_date: &str) -> RttWait {
    parse_iso_date(clock_start);
    parse_iso_date(on_date);
    if on_date < clock_start {
        panic!("onDate {} is before clockStart {}", on_date, clock_start);
    }
    if let Some(stop) = clock_stop {
        parse_iso_date(stop);
        if stop < clock_start {
            panic!("clockStop {} is before clockStart {}", stop, clock_start);
        }
        if stop > on_date {
            panic!("clockStop {} is after onDate {}", stop, on_date);
        }
    }
    let days = days_between(clock_start, clock_stop.unwrap_or(on_date));
    RttWait {
        days,
        completed_weeks: days / 7,
        // The 0-1 week band holds eight days (0 to 7), every later band seven.
        week_band: if days <= 7 { 1 } else { (days + 6) / 7 },
        breached18_weeks: days > EIGHTEEN_WEEKS_DAYS,
        eighteen_week_date: add_days(clock_start, EIGHTEEN_WEEKS_DAYS),
        clock_stopped: clock_stop.is_some(),
    }
}

pub fn rtt_wait_to_value(wait: &RttWait) -> Value {
    Value::obj(vec![
        ("days", Value::Int(wait.days)),
        ("completedWeeks", Value::Int(wait.completed_weeks)),
        ("weekBand", Value::Int(wait.week_band)),
        ("breached18Weeks", Value::Bool(wait.breached18_weeks)),
        ("eighteenWeekDate", Value::str(&wait.eighteen_week_date)),
        ("clockStopped", Value::Bool(wait.clock_stopped)),
    ])
}

fn date_arg(value: &Value) -> &str {
    match value {
        Value::Str(s) => s.as_str(),
        _ => panic!("{:?} is not an ISO date (YYYY-MM-DD)", value),
    }
}

pub fn fune_vector(args: &[Value]) -> Value {
    let stop = if args[1].is_null() { None } else { Some(date_arg(&args[1])) };
    rtt_wait_to_value(&rtt_waiting_time(date_arg(&args[0]), stop, date_arg(&args[2])))
}