extern crate alloc;
use alloc::vec::Vec;
use crate::metis::{Dot, DotFun, DotSet, DotStore, Dotted};
type Register = Dotted<DotFun<&'static str>>;
fn write(reg: &mut Register, station: u32, value: &'static str) -> Dot {
let dot = reg.next_dot(station);
let mut context = DotSet::new();
let _ = context.insert(dot);
for observed in reg.store().dots() {
let _ = context.insert(observed);
}
let store = DotFun::singleton(dot, value);
let delta = Dotted::try_new(store, context).expect("the fresh pair is covered");
*reg = reg.merge(&delta);
dot
}
fn clear_observed(reg: &mut Register) {
let mut context = DotSet::new();
for observed in reg.store().dots() {
let _ = context.insert(observed);
}
let delta = Dotted::from_context(context);
*reg = reg.merge(&delta);
}
#[test]
fn test_register_write_supersedes_observed() {
let mut reg = Register::new();
let d_a = write(&mut reg, 1, "a");
assert_eq!(reg.store().get(d_a), Some(&"a"));
let d_b = write(&mut reg, 1, "b");
assert_eq!(reg.store().get(d_a), None); assert_eq!(reg.store().get(d_b), Some(&"b"));
let live: Vec<&&str> = reg.store().values().collect();
assert_eq!(live, [&"b"]);
assert!(reg.context().contains(d_a));
}
#[test]
fn test_register_concurrent_writes_are_siblings() {
let mut a = Register::new();
let mut b = Register::new();
let d_a = write(&mut a, 1, "alpha"); let d_b = write(&mut b, 2, "beta");
let merged = a.merge(&b);
assert_eq!(merged.store().get(d_a), Some(&"alpha"));
assert_eq!(merged.store().get(d_b), Some(&"beta"));
let mut siblings: Vec<&str> = merged.store().values().copied().collect();
siblings.sort_unstable();
assert_eq!(siblings, ["alpha", "beta"]);
let mut joined = merged;
let d_c = write(&mut joined, 1, "gamma");
assert_eq!(joined.store().get(d_a), None);
assert_eq!(joined.store().get(d_b), None);
let live: Vec<&&str> = joined.store().values().collect();
assert_eq!(live, [&"gamma"]);
assert_eq!(joined.store().get(d_c), Some(&"gamma"));
}
#[test]
fn test_register_observed_clear_empties_without_resurrect() {
let mut a = Register::new();
let d = write(&mut a, 1, "held");
let b = Register::new().merge(&a);
assert_eq!(b.store().get(d), Some(&"held"));
clear_observed(&mut a);
assert!(a.store().is_bottom());
let rejoined = a.merge(&b);
assert!(rejoined.store().is_bottom());
assert_eq!(rejoined, b.merge(&a));
let fresh = Register::new().merge(&a);
assert!(fresh.store().is_bottom());
assert!(fresh.context().contains(d));
}
#[test]
fn test_register_folds_converge_in_both_orders() {
let mut r0 = Register::new();
let mut r1 = Register::new();
let mut r2 = Register::new();
let _ = write(&mut r0, 0, "zero");
let _ = write(&mut r1, 1, "one");
r1 = r1.merge(&r0); let _ = write(&mut r2, 2, "two");
clear_observed(&mut r1);
let replicas = [r0, r1, r2];
let forward = replicas.iter().fold(Register::new(), |acc, r| acc.merge(r));
let backward = replicas
.iter()
.rev()
.fold(Register::new(), |acc, r| acc.merge(r));
assert_eq!(forward, backward);
for r in &replicas {
assert_eq!(&forward.merge(r), &forward);
}
}