extern crate alloc;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::vec::Vec;
use crate::kairos::{Clock, TickCounter};
use crate::metis::{Anchor, Dot, DotSet, Dotted, Locus, Rhapsody};
use super::super::d;
use proptest::prelude::*;
pub(super) type Seq = Dotted<Rhapsody>;
pub(super) const REPLICAS: usize = 3;
#[derive(Clone, Debug)]
pub(super) enum Op {
Insert {
replica: usize,
anchor_pick: usize,
},
Paste {
replica: usize,
anchor_pick: usize,
len: u32,
},
Delete {
replica: usize,
victim_pick: usize,
},
Gossip {
from: usize,
to: usize,
},
}
pub(super) fn arb_ops() -> impl Strategy<Value = Vec<Op>> {
let op = prop_oneof![
(0..REPLICAS, 0usize..8).prop_map(|(replica, anchor_pick)| Op::Insert {
replica,
anchor_pick,
}),
(0..REPLICAS, 0usize..8).prop_map(|(replica, victim_pick)| Op::Delete {
replica,
victim_pick
}),
(0..REPLICAS, 0..REPLICAS).prop_map(|(from, to)| Op::Gossip { from, to }),
];
prop::collection::vec(op, 0..28)
}
pub(super) fn arb_ops_with_paste() -> impl Strategy<Value = Vec<Op>> {
let op = prop_oneof![
4 => (0..REPLICAS, 0usize..8).prop_map(|(replica, anchor_pick)| Op::Insert {
replica,
anchor_pick,
}),
1 => (0..REPLICAS, 0usize..8, 1u32..96).prop_map(|(replica, anchor_pick, len)| {
Op::Paste { replica, anchor_pick, len }
}),
4 => (0..REPLICAS, 0usize..8).prop_map(|(replica, victim_pick)| Op::Delete {
replica,
victim_pick
}),
4 => (0..REPLICAS, 0..REPLICAS).prop_map(|(from, to)| Op::Gossip { from, to }),
];
prop::collection::vec(op, 0..28)
}
pub(super) struct Record {
pub(super) woven: BTreeMap<Dot, Locus>,
pub(super) expelled: BTreeSet<Dot>,
}
pub(super) fn run(ops: &[Op]) -> (Vec<Seq>, Record) {
let mut live: Vec<Seq> = (0..REPLICAS).map(|_| Dotted::new()).collect();
let clocks: Vec<Clock<TickCounter>> = (0..REPLICAS)
.map(|i| {
let station = u32::try_from(i + 1).unwrap();
Clock::with_default_config(TickCounter::new(), station).unwrap()
})
.collect();
let mut record = Record {
woven: BTreeMap::new(),
expelled: BTreeSet::new(),
};
for op in ops {
match *op {
Op::Insert {
replica,
anchor_pick,
} => {
let station = u32::try_from(replica + 1).unwrap();
let visible = live[replica].store().order();
let anchor = if visible.is_empty() {
None
} else {
Some(visible[anchor_pick % visible.len()])
};
let dot = live[replica].next_dot(station);
let rank = clocks[replica].now(0u16);
let locus = Locus {
anchor: anchor.map_or(Anchor::Origin, |dot| Anchor::After(dot.into())),
rank,
};
let mut rhapsody = Rhapsody::new();
assert!(rhapsody.weave(dot, locus));
live[replica] = live[replica].merge(&Dotted::from_store(rhapsody));
let _ = record.woven.insert(dot, locus);
}
Op::Paste {
replica,
anchor_pick,
len,
} => {
let station = u32::try_from(replica + 1).unwrap();
let visible = live[replica].store().order();
let anchor = if visible.is_empty() {
Anchor::Origin
} else {
Anchor::After(visible[anchor_pick % visible.len()].into())
};
let first = live[replica].next_dot(station);
let run = clocks[replica].now_run(core::num::NonZeroU32::new(len).unwrap(), 0u16);
let mut rhapsody = Rhapsody::new();
assert!(rhapsody.weave_run(first, anchor, run));
for k in 0..u64::from(len) {
let dot = d(station, first.counter() + k);
let locus = rhapsody.locus(dot).expect("the run was woven");
let _ = record.woven.insert(dot, locus);
}
live[replica] = live[replica].merge(&Dotted::from_store(rhapsody));
}
Op::Delete {
replica,
victim_pick,
} => {
let visible = live[replica].store().order();
if visible.is_empty() {
continue;
}
let victim = visible[victim_pick % visible.len()];
let mut ctx = DotSet::new();
let _ = ctx.insert(victim);
live[replica] = live[replica].merge(&Dotted::from_context(ctx));
let _ = record.expelled.insert(victim);
}
Op::Gossip { from, to } => {
live[to] = live[to].merge(&live[from]);
}
}
}
(live, record)
}