impl/rust/group_by_due_with_order.rs
2,266 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_day_of_week::day_of_week; ← from dates.day-of-week ^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 todo.item ^1.0.0 · built alongside by fune
use super::todo_item_validate_todo::{todos_from_value, todos_to_value};
const SECTIONS: [(&str, &str); 7] = [
("overdue", "Overdue"),
("today", "Today"),
("tomorrow", "Tomorrow"),
("this-week", "This week"),
("later", "Later"),
("none", "No date"),
("done", "Done"),
];
/// Todos in planner sections, fixed order, empty sections left out. With
/// order "due" the sections spanning several dates are sorted by due date,
/// stably; with "input" every section keeps the caller's order.
///
/// # Panics
/// Panics on an unknown order, or an impossible or malformed date.
pub fn group_by_due_with_order(todos: &[Todo], today: &str, order: &str) -> Vec<DueGroup> {
if order != "due" && order != "input" {
panic!("order must be \"due\" or \"input\", found \"{}\"", order);
}
day_of_week(today); // a bad today is an error even for an empty list
let statuses: Vec<String> = todos.iter().map(|todo| due_status(todo, today)).collect();
let mut groups = Vec::new();
for (status, title) in SECTIONS.iter() {
let mut members: Vec<Todo> = todos
.iter()
.zip(statuses.iter())
.filter(|(_, s)| s.as_str() == *status)
.map(|(todo, _)| todo.clone())
.collect();
if members.is_empty() {
continue;
}
if order == "due" && matches!(*status, "overdue" | "this-week" | "later") {
// sort_by is stable, so equal dates keep input order.
members.sort_by(|a, b| a.due.cmp(&b.due));
}
groups.push(DueGroup { status: status.to_string(), title: title.to_string(), todos: members });
}
groups
}
pub fn due_group_to_value(group: &DueGroup) -> Value {
Value::obj(vec![
("status", Value::str(&group.status)),
("title", Value::str(&group.title)),
("todos", todos_to_value(&group.todos)),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
let groups = group_by_due_with_order(&todos_from_value(&args[0]), args[1].as_str(), args[2].as_str());
Value::Arr(groups.iter().map(due_group_to_value).collect())
}