trellis-core 0.1.2

Deterministic reactive resource graph core types.
Documentation
use std::collections::BTreeSet;
use std::sync::{Arc, Mutex};

use trellis_core::{DependencyList, Graph, ResourceKey, ResourcePlan};

#[derive(Clone, Debug, Eq, PartialEq)]
enum Command {
    Open(String),
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct Output {
    member_count: usize,
}

struct HostComponent {
    graph: Mutex<Graph<Command, Output>>,
}

fn assert_send_sync<T: Send + Sync>() {}

fn set(entries: &[&str]) -> BTreeSet<String> {
    entries.iter().map(|entry| (*entry).to_owned()).collect()
}

#[test]
fn graph_can_live_inside_send_sync_host_component() {
    assert_send_sync::<Graph<Command, Output>>();
    assert_send_sync::<HostComponent>();

    let output_runs = Arc::new(Mutex::new(0_usize));
    let mut graph = Graph::<Command, Output>::new_with_command_type();
    let mut tx = graph.begin_transaction().unwrap();
    let scope = tx.create_scope("host-owned-session").unwrap();
    let source = tx.input::<BTreeSet<String>>("source-members").unwrap();
    tx.set_input(source, set(&["alice", "bob"])).unwrap();

    let member_count = tx
        .derived::<usize>(
            "member-count",
            DependencyList::new([source.id()]).unwrap(),
            move |ctx| Ok(ctx.input(source)?.len()),
        )
        .unwrap();
    let members = tx
        .set_collection(
            "member-resources",
            DependencyList::new([source.id()]).unwrap(),
            move |ctx| Ok(ctx.input(source)?.clone()),
        )
        .unwrap();
    tx.set_resource_planner(members, scope, move |ctx| {
        let mut plan = ResourcePlan::new();
        for added in &ctx.diff().added {
            plan.open(
                ResourceKey::new(format!("member:{}", added.value)),
                ctx.scope(),
                Command::Open(added.value.clone()),
            );
        }
        Ok(plan)
    })
    .unwrap();

    let output_runs_for_materialize = Arc::clone(&output_runs);
    tx.materialized_output(
        "member-output",
        scope,
        DependencyList::new([member_count.id()]).unwrap(),
        move |ctx| {
            *output_runs_for_materialize.lock().unwrap() += 1;
            Ok(Output {
                member_count: *ctx.derived(member_count)?,
            })
        },
    )
    .unwrap();
    let result = tx.commit().unwrap();
    drop(tx);

    assert_eq!(result.resource_plan.commands().len(), 2);
    assert_eq!(result.output_frames.len(), 1);
    assert_eq!(*output_runs.lock().unwrap(), 1);

    let component = HostComponent {
        graph: Mutex::new(graph),
    };
    assert_eq!(component.graph.lock().unwrap().revision(), result.revision);
}