Functional Weave
Code in Rust

todo.due-label@1.0.0

impl/rust.rs

1,741 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::dates_days_between::days_between;  ← from dates.days-between ^1.0.0 · built alongside by fune
use super::todo_due_status::due_status;  ← from todo.due-status ^1.0.0 · built alongside by fune
use super::todo_item::{todo_from_value, Todo};  ← 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",
];

/// The short English label for a todo's due date, built on due_status so the
/// label, the section and the overdue count never disagree.
///
/// # Panics
/// Panics on an impossible or malformed date.
pub fn due_label(todo: &Todo, today: &str) -> String {
    let status = due_status(todo, today);
    let due = match (status.as_str(), &todo.due) {
        ("done", _) | ("none", _) | (_, None) => return String::new(),
        (_, Some(d)) => d.as_str(),
    };
    match status.as_str() {
        "overdue" => {
            let late = days_between(due, today);
            if late == 1 {
                "1 day overdue".to_string()
            } else {
                format!("{} days overdue", late)
            }
        }
        "today" => "Due today".to_string(),
        "tomorrow" => "Due tomorrow".to_string(),
        _ => {
            let d = parse_iso_date(due);
            let label = format!("Due {} {} {}", &day_name(due)[0..3], d.day, MONTHS[(d.month - 1) as usize]);
            // The year only when it differs, so next January never reads as this one.
            if d.year == parse_iso_date(today).year {
                label
            } else {
                format!("{} {}", label, d.year)
            }
        }
    }
}

pub fn fune_vector(args: &[Value]) -> Value {
    Value::str(&due_label(&todo_from_value(&args[0]), args[1].as_str()))
}