Functional Weave
Code in Rust

todo.list@1.1.0

impl/rust/toggle_todo.rs

2,002 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::todo_item::Todo;  ← from todo.item ^1.0.0 · built alongside by fune
use super::todo_item_validate_draft::is_iso_date;
use super::todo_item_validate_todo::{todos_from_value, todos_to_value};
use super::todo_list_add_todo::require_utc_now;  ← addTodo, another function of this group · built into the same file, even by a slim install
use super::todo_list_update_todo::index_of_todo;  ← updateTodo, another function of this group · built into the same file, even by a slim install
use super::todo_next_occurrence::next_occurrence;  ← from todo.next-occurrence ^1.0.0 · built alongside by fune

/// Refuse a today that is not a real YYYY-MM-DD date, whether or not a repeat needs it.
pub fn require_today(today: &str) {
    if !is_iso_date(today) {
        panic!("today must be a date like 2026-09-28");
    }
}

/// Complete one open todo. A one-off is done at `now`; a repeating one stays
/// open and rolls forward to its next occurrence (todo.next-occurrence).
pub fn complete_todo(todo: &Todo, now: &str, today: &str) -> Todo {
    let mut next = todo.clone();
    match (&todo.recurrence, todo.due.as_deref()) {
        (None, _) => {
            next.done = true;
            next.completed_at = Some(now.to_string());
        }
        (Some(_), None) => panic!("repeating todo \"{}\" has no due date", todo.id),
        (Some(rule), Some(due)) => {
            next.done = false;
            next.completed_at = None;
            next.due = Some(next_occurrence(rule, due, today));
        }
    }
    next
}

/// Tick or untick one todo. Reopening clears the completion time.
///
/// # Panics
/// On an unknown id, a `now` that is not a UTC timestamp or a `today` that is
/// not a date.
pub fn toggle_todo(todos: &[Todo], id: &str, now: &str, today: &str) -> Vec<Todo> {
    let at = index_of_todo(todos, id);
    require_utc_now(now);
    require_today(today);
    let mut out = todos.to_vec();
    if out[at].done {
        out[at].done = false;
        out[at].completed_at = None;
    } else {
        out[at] = complete_todo(&todos[at], now, today);
    }
    out
}

pub fn fune_vector(args: &[Value]) -> Value {
    let todos = todos_from_value(&args[0]);
    todos_to_value(&toggle_todo(&todos, args[1].as_str(), args[2].as_str(), args[3].as_str()))
}