use super::super::super::support::dot;
use crate::metis::{Anchor, Dot, DotSet, DotStore, Kind, KindPlurality, Locus};
use super::super::{TestNode, rank};
#[derive(Clone, Debug, PartialEq, Eq)]
enum Sum {
Left(DotSet),
Right(DotSet),
}
impl Default for Sum {
fn default() -> Self {
Self::Left(DotSet::new())
}
}
impl Sum {
fn set(&self) -> &DotSet {
match self {
Self::Left(set) | Self::Right(set) => set,
}
}
}
impl DotStore for Sum {
fn dots(&self) -> impl Iterator<Item = Dot> + '_ {
DotStore::dots(self.set())
}
fn is_bottom(&self) -> bool {
self.set().is_bottom()
}
fn causal_merge(&self, self_context: &DotSet, other: &Self, other_context: &DotSet) -> Self {
let bottom = DotSet::new();
let (mine, theirs) = (self.set(), other.set());
let kept = match (self, other) {
(Self::Left(_), Self::Left(_)) | (Self::Right(_), Self::Right(_)) => {
mine.causal_merge(self_context, theirs, other_context)
}
(Self::Left(_) | Self::Right(_), _) => {
mine.causal_merge(self_context, &bottom, other_context)
}
};
match self {
Self::Left(_) => Self::Left(kept),
Self::Right(_) => Self::Right(kept),
}
}
fn restrict(&self, roster: impl IntoIterator<Item = u32>) -> Self {
match self {
Self::Left(set) => Self::Left(DotStore::restrict(set, roster)),
Self::Right(set) => Self::Right(DotStore::restrict(set, roster)),
}
}
fn novel_to(&self, context: &DotSet) -> Self {
match self {
Self::Left(set) => Self::Left(DotStore::novel_to(set, context)),
Self::Right(set) => Self::Right(DotStore::novel_to(set, context)),
}
}
}
#[test]
fn test_a_sum_shaped_merge_cannot_keep_the_survivor_law() {
let mut left_set = DotSet::new();
assert!(left_set.insert(dot(1, 1)));
let a = Sum::Left(left_set.clone());
let a_ctx = left_set;
let mut right_set = DotSet::new();
assert!(right_set.insert(dot(2, 1)));
let b = Sum::Right(right_set.clone());
let b_ctx = right_set;
let ab = a.causal_merge(&a_ctx, &b, &b_ctx);
assert!(
!ab.dots().any(|held| held == dot(2, 1)),
"the sum kept self's shape and discarded the other side's uncovered dot"
);
let ba = b.causal_merge(&b_ctx, &a, &a_ctx);
assert!(
!ba.dots().any(|held| held == dot(1, 1)),
"the mirrored merge discards the mirrored dot"
);
assert_ne!(ab, ba, "and no sum-shaped rule is even commutative here");
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
struct Exclusive {
tag: Option<(Dot, Kind)>,
content: DotSet,
}
impl DotStore for Exclusive {
fn dots(&self) -> impl Iterator<Item = Dot> + '_ {
self.tag
.iter()
.map(|&(dot, _)| dot)
.chain(DotStore::dots(&self.content))
}
fn is_bottom(&self) -> bool {
self.tag.is_none() && self.content.is_bottom()
}
fn causal_merge(&self, _: &DotSet, other: &Self, _: &DotSet) -> Self {
let winner = match (self.tag, other.tag) {
(Some(mine), Some(theirs)) if theirs.0 > mine.0 => other,
(None, Some(_)) => other,
_ => self,
};
winner.clone()
}
fn restrict(&self, roster: impl IntoIterator<Item = u32>) -> Self {
Self {
tag: self.tag,
content: DotStore::restrict(&self.content, roster),
}
}
fn novel_to(&self, context: &DotSet) -> Self {
Self {
tag: self.tag,
content: DotStore::novel_to(&self.content, context),
}
}
}
#[test]
fn test_an_exclusive_kind_merge_discards_a_concurrent_subtree() {
let mut a_content = DotSet::new();
assert!(a_content.insert(dot(1, 2)));
let a = Exclusive {
tag: Some((dot(1, 1), Kind::Register)),
content: a_content,
};
let mut a_ctx = DotSet::new();
assert!(a_ctx.insert(dot(1, 1)));
assert!(a_ctx.insert(dot(1, 2)));
let mut b_content = DotSet::new();
assert!(b_content.insert(dot(2, 2)));
let b = Exclusive {
tag: Some((dot(2, 1), Kind::Sequence)),
content: b_content,
};
let mut b_ctx = DotSet::new();
assert!(b_ctx.insert(dot(2, 1)));
assert!(b_ctx.insert(dot(2, 2)));
let merged = a.causal_merge(&a_ctx, &b, &b_ctx);
assert!(
!merged.dots().any(|held| held == dot(1, 2)),
"A's concurrent subtree is silently gone, unrecoverably: \
b's context never covered (1, 2), so the survivor law demanded it live"
);
let mut node_a = TestNode::new();
assert!(node_a.write_tag(dot(1, 1), Kind::Register));
assert!(node_a.write_register(dot(1, 2), "a"));
let mut node_b = TestNode::new();
assert!(node_b.write_tag(dot(2, 1), Kind::Sequence));
assert!(node_b.weave(
dot(2, 2),
Locus {
anchor: Anchor::Origin,
rank: rank(1),
}
));
let merged = node_a.causal_merge(&a_ctx, &node_b, &b_ctx);
assert!(merged.dots().any(|held| held == dot(1, 2)));
assert!(merged.dots().any(|held| held == dot(2, 2)));
assert_eq!(merged.kinds_present().len(), 2, "surfaced, not resolved");
}
#[test]
fn test_slots_alone_cannot_say_conflict_but_the_node_must() {
let mut node = TestNode::new();
assert!(node.write_register(dot(1, 1), "register-me"));
assert!(node.weave(
dot(2, 1),
Locus {
anchor: Anchor::Origin,
rank: rank(1),
}
));
assert_eq!(node.register().values().count(), 1);
assert_eq!(node.sequence().visible_len(), 1);
assert_eq!(node.kinds_present().len(), 2);
assert!(matches!(node.sole(), Err(KindPlurality { .. })));
}