extern crate alloc;
use alloc::vec::Vec;
use crate::kairos::Kairos;
use crate::metis::{Anchor, Composer, DotSet, Dotted, Locus, Retired, Rhapsody};
use super::reference::reference_order;
use super::wire::round_trip_rhapsody;
use super::{Dot, Fleet, REPLICAS, station_of};
fn assert_index_insertion(pre: &[Dot], post: &[Dot], minted: Dot, index: usize) {
let mut expected: Vec<Dot> = pre.to_vec();
expected.insert(index, minted);
assert_eq!(
post, expected,
"a freshest-rank weave must land at its intended index",
);
}
pub(super) fn weave(fleet: &mut Fleet, replica: usize, argument: u8, tick: &mut u64) {
let station = station_of(replica);
let visible = fleet.live[replica].state().store().order();
let (anchor, intended) = if visible.is_empty() {
(Anchor::Origin, 0)
} else {
let slot = usize::from(argument) % visible.len();
(Anchor::After(visible[slot].into()), slot + 1)
};
let rank = Kairos::new(*tick, 0u16, station, 0u16);
*tick += 1;
let (minted, delta) = fleet.live[replica].compose(|assigned| {
let mut rhapsody = Rhapsody::new();
let _ = rhapsody.weave(assigned, Locus { anchor, rank });
(rhapsody, DotSet::new())
});
round_trip_rhapsody(delta.store());
round_trip_rhapsody(fleet.live[replica].state().store());
let post = fleet.live[replica].state().store().order();
assert_index_insertion(&visible, &post, minted, intended);
let _ = fleet.ledger.observe(&post);
}
pub(super) fn weave_before(fleet: &mut Fleet, replica: usize, argument: u8, tick: &mut u64) {
let station = station_of(replica);
let visible = fleet.live[replica].state().store().order();
let intended = if visible.is_empty() {
0
} else {
usize::from(argument) % visible.len()
};
let after = if intended == 0 {
None
} else {
Some(visible[intended - 1])
};
let anchor = fleet.live[replica]
.state()
.store()
.anchor_for_visual_insert(after.map(Into::into));
let rank = Kairos::new(*tick, 0u16, station, 0u16);
*tick += 1;
let (minted, delta) = fleet.live[replica].compose(|assigned| {
let mut rhapsody = Rhapsody::new();
let _ = rhapsody.weave(assigned, Locus { anchor, rank });
(rhapsody, DotSet::new())
});
round_trip_rhapsody(delta.store());
round_trip_rhapsody(fleet.live[replica].state().store());
let post = fleet.live[replica].state().store().order();
assert_index_insertion(&visible, &post, minted, intended);
let _ = fleet.ledger.observe(&post);
}
pub(super) fn retract(fleet: &mut Fleet, replica: usize, argument: u8) {
let visible = fleet.live[replica].state().store().order();
if visible.is_empty() {
return;
}
let victim = visible[usize::from(argument) % visible.len()];
let _ = fleet.ever_removed.insert(victim);
let mut superseded = DotSet::new();
let _ = superseded.insert(victim);
let _ = fleet.live[replica].retract(superseded);
round_trip_rhapsody(fleet.live[replica].state().store());
let post = fleet.live[replica].state().store().order();
let _ = fleet.ledger.observe(&post);
}
pub(super) fn gossip_delta(fleet: &mut Fleet, replica: usize, other: usize) {
if replica == other {
return;
}
let peer_context = fleet.live[replica].state().context().clone();
let delta = fleet.live[other].owed_to(&peer_context);
round_trip_rhapsody(delta.store());
let _ = fleet.live[replica].absorb(station_of(other), &delta);
round_trip_rhapsody(fleet.live[replica].state().store());
let post = fleet.live[replica].state().store().order();
let _ = fleet.ledger.observe(&post);
}
pub(super) fn gossip_full(fleet: &mut Fleet, replica: usize, other: usize) {
if replica == other {
return;
}
let full = fleet.live[other].state().clone();
round_trip_rhapsody(full.store());
let _ = fleet.live[replica].absorb(station_of(other), &full);
let post = fleet.live[replica].state().store().order();
let _ = fleet.ledger.observe(&post);
}
pub(super) fn condense_all(fleet: &mut Fleet) {
let mut retired = DotSet::new();
for &dot in &fleet.ever_removed {
let invisible_everywhere = fleet
.live
.iter()
.all(|r| !r.state().store().is_visible(dot));
if invisible_everywhere {
let _ = retired.insert(dot);
}
}
let retired = Retired::trust(retired);
for i in 0..REPLICAS {
let mut rhapsody = fleet.live[i].state().store().clone();
let _ = rhapsody.condense(&retired);
let context = fleet.live[i].state().context().clone();
let rebuilt =
Dotted::try_new(rhapsody, context).unwrap_or_else(|_| fleet.live[i].state().clone());
let before = fleet.live[i].state().store().order();
let after = rebuilt.store().order();
assert_eq!(before, after, "condense preserves order at every replica");
fleet.live[i] = Composer::adopt(station_of(i), rebuilt);
let _ = fleet.ledger.observe(&after);
}
}
pub(super) fn order_read(fleet: &mut Fleet, replica: usize) {
let rhapsody = fleet.live[replica].state().store();
let got = rhapsody.order();
let reference = reference_order(rhapsody);
assert_eq!(got, reference, "order() matches the independent reference");
let _ = fleet.ledger.observe(&got);
}