minerva 0.2.0

Causal ordering for distributed systems
extern crate alloc;

use super::model::Record;
use crate::kairos::Kairos;
use crate::metis::{Anchor, Dot, Locus};
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::vec::Vec;

pub(super) fn reference_order(record: &Record) -> Vec<Dot> {
    enum Frame {
        Visit(Dot),
        Emit(Dot),
    }

    let woven: &BTreeMap<Dot, Locus> = &record.woven;
    // Group every child under its anchor once (the record is the only
    // input, so the oracle stays independent of the production planes; the
    // grouping only retires the per-visit whole-record rescan, which the
    // paste-bearing model made quadratic in practice).
    let mut buckets: BTreeMap<Anchor, Vec<Dot>> = BTreeMap::new();
    for (&dot, locus) in woven {
        buckets.entry(locus.anchor).or_default().push(dot);
    }
    for kids in buckets.values_mut() {
        kids.sort_by(|a, b| {
            let (ra, rb): (Kairos, Kairos) = (woven[a].rank, woven[b].rank);
            rb.cmp(&ra).then_with(|| a.cmp(b))
        });
    }
    let bucket = |anchor: Anchor| -> Vec<Dot> { buckets.get(&anchor).cloned().unwrap_or_default() };

    let mut order = Vec::new();
    let mut stack: Vec<Frame> = bucket(Anchor::Origin)
        .into_iter()
        .rev()
        .map(Frame::Visit)
        .collect();
    while let Some(frame) = stack.pop() {
        match frame {
            Frame::Emit(dot) => {
                if !record.expelled.contains(&dot) {
                    order.push(dot);
                }
            }
            Frame::Visit(dot) => {
                for kid in bucket(Anchor::After(dot.into())).into_iter().rev() {
                    stack.push(Frame::Visit(kid));
                }
                stack.push(Frame::Emit(dot));
                for kid in bucket(Anchor::Before(dot.into())) {
                    stack.push(Frame::Visit(kid));
                }
            }
        }
    }
    order
}

#[test]
fn test_reference_handles_the_empty_run() {
    let record = Record {
        woven: BTreeMap::new(),
        expelled: BTreeSet::new(),
    };
    assert_eq!(reference_order(&record), Vec::<Dot>::new());
}