extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use crate::metis::{Dot, DotSet, DotStore, Dotted};
use super::Inscribed;
type Register = Dotted<Inscribed>;
fn context_of(dots: &[Dot]) -> DotSet {
let mut set = DotSet::new();
for &dot in dots {
assert!(set.insert(dot));
}
set
}
fn write(reg: &mut Register, station: u32, value: &str) -> (Register, Dot) {
let fresh = reg.next_dot(station);
let mut context = context_of(&[fresh]);
let observed: Vec<Dot> = reg.store().dots().collect();
for &obs in &observed {
let _ = context.insert(obs);
}
let store = Inscribed::singleton(fresh, String::from(value));
let delta = Dotted::try_new(store, context).expect("the fresh pair is covered by construction");
*reg = reg.merge(&delta);
(delta, fresh)
}
fn clear_observed(reg: &mut Register) -> 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);
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().value(d_a), Some(&String::from("a")));
let (_, d_b) = write(&mut reg, 1, "b");
assert!(!reg.store().holds(d_a));
assert_eq!(reg.store().value(d_b), Some(&String::from("b")));
let live: Vec<Dot> = reg.store().dots().collect();
assert_eq!(live, [d_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().value(d_a), Some(&String::from("alpha")));
assert_eq!(merged.store().value(d_b), Some(&String::from("beta")));
let mut siblings: Vec<Dot> = merged.store().dots().collect();
siblings.sort_unstable();
assert_eq!(siblings, [d_a, d_b]);
let mut joined = merged;
let (_, d_c) = write(&mut joined, 1, "gamma");
assert!(!joined.store().holds(d_a));
assert!(!joined.store().holds(d_b));
let live: Vec<Dot> = joined.store().dots().collect();
assert_eq!(live, [d_c]);
assert_eq!(joined.store().value(d_c), Some(&String::from("gamma")));
}
#[test]
fn test_register_observed_clear_empties_without_resurrect() {
let mut a = Register::new();
let (_, d) = write(&mut a, 1, "held");
let mut b = Register::new();
b = b.merge(&a);
assert_eq!(b.store().value(d), Some(&String::from("held")));
let _ = 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");
let _ = 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);
}
}