Functional Weave
Code in Python

todo.recurrence-label@1.0.0

impl/rust.rs

2,438 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::parse_iso_date;  ← from dates.add-days ^1.0.0 · built alongside by fune
use super::dates_day_of_week::day_name;  ← from dates.day-of-week ^1.0.0 · built alongside by fune
use super::todo_item::{recurrence_from_value, Recurrence};  ← from todo.item ^1.0.0 · built alongside by fune

const MONTHS: [&str; 12] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

/// 1st, 2nd, 3rd, 4th ... 11th, 12th, 13th ... 21st, 22nd, 23rd ... 31st.
fn ordinal(n: i64) -> String {
    if (11..=13).contains(&(n % 100)) {
        return format!("{}th", n);
    }
    let suffix = match n % 10 {
        1 => "st",
        2 => "nd",
        3 => "rd",
        _ => "th",
    };
    format!("{}{}", n, suffix)
}

fn every(interval: i64, unit: &str) -> String {
    if interval == 1 {
        format!("Every {}", unit)
    } else {
        format!("Every {} {}s", interval, unit)
    }
}

/// English words for a repeat rule; the weekday, day and date come from the anchor.
///
/// # Panics
/// Panics on an unknown frequency, an interval below 1 (or other than 1 for
/// weekdays), or an anchor that is not a real ISO date.
pub fn recurrence_label(recurrence: &Recurrence) -> String {
    let frequency = recurrence.frequency.as_str();
    let interval = recurrence.interval;
    if !["daily", "weekdays", "weekly", "monthly", "yearly"].contains(&frequency) {
        panic!(
            "unknown repeat frequency \"{}\": expected daily, weekdays, weekly, monthly or yearly",
            frequency
        );
    }
    if interval < 1 {
        panic!("repeat interval must be 1 or more, received {}", interval);
    }
    if frequency == "weekdays" && interval != 1 {
        panic!("weekday repeats cannot skip weeks: interval must be 1, received {}", interval);
    }
    let date = parse_iso_date(&recurrence.anchor);
    match frequency {
        "daily" => every(interval, "day"),
        "weekdays" => "Every weekday".to_string(),
        "weekly" => format!("{} on {}", every(interval, "week"), day_name(&recurrence.anchor)),
        "monthly" => format!("{} on the {}", every(interval, "month"), ordinal(date.day)),
        _ => format!("{} on {} {}", every(interval, "year"), date.day, MONTHS[(date.month - 1) as usize]),
    }
}

pub fn fune_vector(args: &[Value]) -> Value {
    if let Value::Float(f) = args[0].get("interval") {
        panic!("repeat interval must be 1 or more, received {}", f);
    }
    let rule = recurrence_from_value(&args[0]).expect("a recurrence");
    Value::Str(recurrence_label(&rule))
}