extern crate alloc;
use alloc::vec::Vec;
use super::super::support::dot;
use crate::metis::{Composer, DotMap, DotSet, Dotted, Purview};
use proptest::prelude::*;
mod common;
mod owed;
mod rows;
type Doc = Dotted<DotMap<u8, DotSet>>;
const REPLICAS: usize = 3;
#[derive(Clone, Debug)]
enum Op {
Add { replica: usize, key: u8 },
Remove { replica: usize, key: u8 },
Gossip { from: usize, to: usize },
}
fn arb_ops() -> impl Strategy<Value = Vec<Op>> {
let op = prop_oneof![
(0..REPLICAS, 0u8..3).prop_map(|(replica, key)| Op::Add { replica, key }),
(0..REPLICAS, 0u8..3).prop_map(|(replica, key)| Op::Remove { replica, key }),
(0..REPLICAS, 0..REPLICAS).prop_map(|(from, to)| Op::Gossip { from, to }),
];
prop::collection::vec(op, 0..24)
}
fn station_of(replica: usize) -> u32 {
u32::try_from(replica + 1).unwrap()
}
fn roster() -> Vec<u32> {
(0..REPLICAS).map(station_of).collect()
}
struct Transcript {
live: Vec<Doc>,
trackers: Vec<Purview>,
}
fn run(ops: &[Op]) -> Transcript {
let roster = roster();
let mut live: Vec<Doc> = (0..REPLICAS).map(|_| Dotted::new()).collect();
let mut trackers: Vec<Purview> = (0..REPLICAS)
.map(|_| Purview::new(roster.iter().copied()))
.collect();
for op in ops {
match *op {
Op::Add { replica, key } => {
let fresh = live[replica].next_dot(station_of(replica));
let mut held = DotSet::new();
assert!(held.insert(fresh));
let delta = Dotted::from_store(DotMap::singleton(key, held));
live[replica] = live[replica].merge(&delta);
}
Op::Remove { replica, key } => {
let observed = live[replica].store().get(&key).cloned().unwrap_or_default();
let delta = Dotted::from_context(observed);
live[replica] = live[replica].merge(&delta);
}
Op::Gossip { from, to } => {
let mut sink = Composer::adopt(station_of(to), live[to].clone());
let received = sink.absorb(station_of(from), &live[from]);
live[to] = sink.state().clone();
trackers[to].note(&received).unwrap();
}
}
}
Transcript { live, trackers }
}
fn model_common(purview: &Purview, roster: &[u32]) -> DotSet {
let mut rows = roster.iter().map(|&peer| purview.of(peer).unwrap());
let Some(first) = rows.next() else {
return DotSet::new();
};
rows.fold(first.clone(), |acc, row| acc.intersect(row))
}
fn arb_notes() -> impl Strategy<Value = Vec<(u32, DotSet)>> {
let evidence = prop::collection::vec((1u32..=4, 1u64..6), 0..6).prop_map(|pairs| {
let mut set = DotSet::new();
for (station, counter) in pairs {
let _ = set.insert(dot(station, counter));
}
set
});
prop::collection::vec((station_of(0)..=station_of(REPLICAS - 1), evidence), 0..16)
}