extern crate alloc;
use alloc::collections::BTreeSet;
use alloc::vec::Vec;
use crate::kairos::Kairos;
use crate::metis::{Anchor, Dot, DotSet, DotStore, Dotted, Locus, Rhapsody};
use super::super::d;
use super::clock;
fn two_ranks() -> (Kairos, Kairos) {
let clk = clock(1);
(clk.now(0u16), clk.now(0u16))
}
fn covered(rhapsody: &Rhapsody) -> DotSet {
let mut ctx = DotSet::new();
for dot in rhapsody.dots() {
let _ = ctx.insert(dot);
}
for station in 0u32..4 {
for counter in 1u64..6 {
if rhapsody.locus(d(station, counter)).is_some() {
let _ = ctx.insert(d(station, counter));
}
}
}
ctx
}
fn sample(station: u32, live: &[u64], tombstones: &[u64]) -> Rhapsody {
let (r0, r1) = two_ranks();
let mut rhapsody = Rhapsody::new();
let mut prev: Option<(u32, u64)> = None;
let mut all: Vec<u64> = live.iter().chain(tombstones).copied().collect();
all.sort_unstable();
all.dedup();
for &dot in &all {
let rank = if dot % 2 == 0 { r0 } else { r1 };
let anchor = prev.map_or(Anchor::Origin, |raw: (u32, u64)| Anchor::After(raw.into()));
assert!(rhapsody.weave(d(station, dot), Locus { anchor, rank }));
prev = Some((station, dot));
}
let mut ctx = DotSet::new();
for &dot in tombstones {
let _ = ctx.insert(d(station, dot));
}
let live_pair = Dotted::try_new(rhapsody.clone(), covered(&rhapsody)).unwrap();
let removal = Dotted::from_context(ctx);
live_pair.merge(&removal).store().clone()
}
#[test]
fn test_conformance_survivor_law_on_the_visible_coordinate() {
let a = sample(1, &[1, 2, 3], &[]);
let b = sample(1, &[1], &[2]);
let a_ctx = covered(&a);
let b_ctx = covered(&b);
let merged = a.causal_merge(&a_ctx, &b, &b_ctx);
let support: BTreeSet<Dot> = merged.dots().collect();
assert!(support.contains(&d(1, 1)));
assert!(!support.contains(&d(1, 2)));
assert!(support.contains(&d(1, 3)));
assert!(merged.locus(d(1, 1)).is_some());
assert!(merged.locus(d(1, 2)).is_some());
assert!(merged.locus(d(1, 3)).is_some());
}
#[test]
fn test_conformance_merge_is_a_semilattice_join() {
let a = sample(1, &[1, 2], &[3]);
let b = sample(1, &[1], &[2]);
let c = sample(2, &[1, 2], &[]);
let (actx, bctx, cctx) = (covered(&a), covered(&b), covered(&c));
let ab = a.causal_merge(&actx, &b, &bctx);
let ba = b.causal_merge(&bctx, &a, &actx);
assert_eq!(ab, ba);
let bc = b.causal_merge(&bctx, &c, &cctx);
let bc_ctx = bctx.merge(&cctx);
let left = a.causal_merge(&actx, &bc, &bc_ctx);
let ab_ctx = actx.merge(&bctx);
let right = ab.causal_merge(&ab_ctx, &c, &cctx);
assert_eq!(left, right);
assert_eq!(a.causal_merge(&actx, &a, &actx), a);
let bottom = Rhapsody::new();
let empty = DotSet::new();
assert_eq!(a.causal_merge(&actx, &bottom, &empty), a);
assert_eq!(bottom.causal_merge(&empty, &a, &actx), a);
}
#[test]
fn test_conformance_restriction_is_fiber_selection() {
let a = {
let mut w = sample(1, &[1, 2], &[]);
let extra = sample(2, &[1], &[]);
let actx = covered(&w);
let ectx = covered(&extra);
w = w.causal_merge(&actx, &extra, &ectx);
w
};
let b = sample(2, &[1, 2], &[]);
let roster = [1u32];
let kept = a.restrict(roster);
let support: Vec<Dot> = kept.dots().collect();
assert!(support.iter().all(|dot| dot.station() == 1));
assert!(kept.locus(d(2, 1)).is_none());
let actx = covered(&a);
let bctx = covered(&b);
let merged = a.causal_merge(&actx, &b, &bctx);
let restrict_then_merge = a.restrict(roster).causal_merge(
&actx.restrict(roster),
&b.restrict(roster),
&bctx.restrict(roster),
);
assert_eq!(merged.restrict(roster), restrict_then_merge);
}
#[test]
fn test_conformance_novel_to_selects_uncovered_dots() {
let a = sample(1, &[1, 2, 3], &[]);
let mut peer = DotSet::new();
assert!(peer.insert(d(1, 1)));
assert!(peer.insert(d(1, 2)));
let novel = a.novel_to(&peer);
let support: Vec<Dot> = novel.dots().collect();
assert_eq!(support, [d(1, 3)]);
assert!(novel.locus(d(1, 3)).is_some());
assert!(novel.locus(d(1, 1)).is_some());
assert!(novel.locus(d(1, 2)).is_some());
}