Functional Weave
Code in Rust

todo.merge@1.0.0

impl/rust.rs

1,646 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 std::collections::HashSet;

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_todo::{todos_from_value, todos_to_value};

/// Manual order: order ascending, ties by position (sort_by_key is stable).
fn in_manual_order(todos: &[Todo], which: &str) -> Vec<Todo> {
    let mut seen: HashSet<&str> = HashSet::new();
    for todo in todos {
        if !seen.insert(todo.id.as_str()) {
            panic!("duplicate id \"{}\" in the {} list", todo.id, which);
        }
    }
    let mut sorted = todos.to_vec();
    sorted.sort_by_key(|todo| todo.order);
    sorted
}

/// Merge by id: a todo in both lists is taken from `incoming`, in the place
/// the current one had; todos only in `incoming` follow in their own manual
/// order. The result is in manual order, renumbered 0 to n-1.
///
/// # Panics
/// On an id that appears twice in either list.
pub fn merge_todos(current: &[Todo], incoming: &[Todo]) -> Vec<Todo> {
    let mine = in_manual_order(current, "current");
    let theirs = in_manual_order(incoming, "incoming");
    let kept: HashSet<&str> = mine.iter().map(|todo| todo.id.as_str()).collect();
    let mut merged: Vec<Todo> = mine
        .iter()
        .map(|todo| theirs.iter().find(|t| t.id == todo.id).unwrap_or(todo).clone())
        .collect();
    merged.extend(theirs.iter().filter(|todo| !kept.contains(todo.id.as_str())).cloned());
    for (order, todo) in merged.iter_mut().enumerate() {
        todo.order = order as i64;
    }
    merged
}

pub fn fune_vector(args: &[Value]) -> Value {
    todos_to_value(&merge_todos(&todos_from_value(&args[0]), &todos_from_value(&args[1])))
}