extern crate alloc;
use alloc::vec::Vec;
use proptest::prelude::*;
use crate::metis::{Anchor, DotSet, Dotted, Kind, Locus, Node};
use super::{Author, TestNode, rank};
mod convergence;
mod reads;
#[derive(Clone, Debug)]
enum Op {
Tag { author: usize, key: u8, kind: usize },
Value { author: usize, key: u8 },
Weave { author: usize, key: u8 },
Rekind { author: usize, key: u8, kind: usize },
Retract { author: usize, key: u8 },
Gossip { from: usize, to: usize },
Deliver { pick: usize, to: usize },
}
fn kind_of(index: usize) -> Kind {
match index % 3 {
0 => Kind::Register,
1 => Kind::Map,
_ => Kind::Sequence,
}
}
fn arb_op() -> impl Strategy<Value = Op> {
prop_oneof![
(0usize..3, 0u8..3, 0usize..3).prop_map(|(author, key, kind)| Op::Tag {
author,
key,
kind
}),
(0usize..3, 0u8..3).prop_map(|(author, key)| Op::Value { author, key }),
(0usize..3, 0u8..3).prop_map(|(author, key)| Op::Weave { author, key }),
(0usize..3, 0u8..3, 0usize..3).prop_map(|(author, key, kind)| Op::Rekind {
author,
key,
kind
}),
(0usize..3, 0u8..3).prop_map(|(author, key)| Op::Retract { author, key }),
(0usize..3, 0usize..3).prop_map(|(from, to)| Op::Gossip { from, to }),
(0usize..64, 0usize..3).prop_map(|(pick, to)| Op::Deliver { pick, to }),
]
}
fn arb_ops() -> impl Strategy<Value = Vec<Op>> {
prop::collection::vec(arb_op(), 0..32)
}
fn page_with(key: u8, block: TestNode) -> TestNode {
let mut page = TestNode::new();
assert!(page.insert_child(key, block));
page
}
fn observed_under(held: &TestNode, key: u8) -> DotSet {
held.children()
.get(&key)
.map(Node::observed)
.unwrap_or_default()
}
fn apply(fleet: &mut [Author; 3], wire: &mut Vec<(u32, Dotted<TestNode>)>, op: &Op, serial: u64) {
match *op {
Op::Tag { author, key, kind } => {
let (_, delta) = fleet[author].compose_super(
|dot| {
let mut block = TestNode::new();
assert!(block.write_tag(dot, kind_of(kind)));
page_with(key, block)
},
|held| {
held.children()
.get(&key)
.map(|block| block.tag().observed())
.unwrap_or_default()
},
);
wire.push((fleet[author].station(), delta));
}
Op::Value { author, key } => {
let (_, delta) = fleet[author].compose_super(
|dot| {
let mut block = TestNode::new();
assert!(block.write_register(dot, "v"));
page_with(key, block)
},
|held| {
held.children()
.get(&key)
.map(|block| block.register().observed())
.unwrap_or_default()
},
);
wire.push((fleet[author].station(), delta));
}
Op::Weave { author, key } => {
let (_, delta) = fleet[author].compose(|dot| {
let mut block = TestNode::new();
assert!(block.weave(
dot,
Locus {
anchor: Anchor::Origin,
rank: rank(serial),
}
));
(page_with(key, block), DotSet::new())
});
wire.push((fleet[author].station(), delta));
}
Op::Rekind { author, key, kind } => {
let (_, delta) = fleet[author].compose_super(
|dot| {
let mut block = TestNode::new();
assert!(block.write_tag(dot, kind_of(kind)));
page_with(key, block)
},
|held| observed_under(held, key),
);
wire.push((fleet[author].station(), delta));
}
Op::Retract { author, key } => {
let superseded = observed_under(fleet[author].state().store(), key);
let delta = fleet[author].retract(superseded);
wire.push((fleet[author].station(), delta));
}
Op::Gossip { from, to } => {
if from != to {
let delta = fleet[from].owed_to(fleet[to].state().context());
let station = fleet[from].station();
let _ = fleet[to].absorb(station, &delta);
}
}
Op::Deliver { pick, to } => {
if !wire.is_empty() {
let (station, delta) = wire[pick % wire.len()].clone();
let _ = fleet[to].absorb(station, &delta);
}
}
}
}
fn run(ops: &[Op]) -> [Author; 3] {
let mut fleet = [Author::new(1), Author::new(2), Author::new(3)];
let mut wire: Vec<(u32, Dotted<TestNode>)> = Vec::new();
for (index, op) in ops.iter().enumerate() {
apply(&mut fleet, &mut wire, op, index as u64);
}
fleet
}
fn settle(fleet: &mut [Author; 3]) {
for _ in 0..2 {
for from in 0..3 {
for to in 0..3 {
if from != to {
let delta = fleet[from].owed_to(fleet[to].state().context());
let station = fleet[from].station();
let _ = fleet[to].absorb(station, &delta);
}
}
}
}
}