extern crate alloc;
use alloc::collections::BTreeMap;
use core::num::NonZeroU64;
use crate::kairos::Kairos;
use crate::metis::metathesis::Metatheses;
use crate::metis::{DotSet, VersionVector};
use super::Rhapsody;
use super::placement::{Anchor, Dot, Locus};
use super::wire::apply_chain_step;
mod pure;
mod wire;
pub use wire::{RefoundMapDecodeBudget, RefoundMapDecodeError};
use pure::remint;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UnsealedStratum {
pub dot: Dot,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RefoundMap {
compacted: BTreeMap<Dot, Dot>,
ceilings: VersionVector,
live: BTreeMap<u32, u64>,
}
impl RefoundMap {
pub(crate) fn bind_cut(&mut self, cut: &crate::metis::Cut) {
debug_assert!(
self.compacted
.keys()
.all(|dot| dot.counter() <= cut.as_vector().get(dot.station()))
);
self.ceilings = cut.as_vector().clone();
}
#[must_use]
pub fn translate(&self, dot: Dot) -> Option<Dot> {
if let Some(&new) = self.compacted.get(&dot) {
return Some(new);
}
let ceiling = self.ceilings.get(dot.station());
if dot.counter() > ceiling {
let live = self.live.get(&dot.station()).copied().unwrap_or(0);
return NonZeroU64::new(affine(live, ceiling, dot.counter()))
.map(|counter| Dot::new(dot.station(), counter));
}
None
}
#[must_use]
pub fn live_len(&self) -> usize {
self.compacted.len()
}
#[cfg(feature = "instrumentation")]
pub(crate) fn structural_counts(&self) -> (usize, usize, usize) {
(
self.compacted.len(),
self.ceilings.iter().count(),
self.live.len(),
)
}
pub(crate) fn live_of(&self, station: u32) -> u64 {
self.live.get(&station).copied().unwrap_or(0)
}
pub(crate) fn ceiling_of(&self, station: u32) -> u64 {
self.ceilings.get(station)
}
}
fn affine(live: u64, ceiling: u64, dot: u64) -> u64 {
debug_assert!(live <= ceiling && ceiling < dot);
live + (dot - ceiling)
}
#[derive(Clone, Debug)]
pub struct Refounded {
store: Rhapsody,
map: RefoundMap,
}
impl Refounded {
#[must_use]
pub const fn store(&self) -> &Rhapsody {
&self.store
}
#[must_use]
pub const fn map(&self) -> &RefoundMap {
&self.map
}
#[must_use]
pub fn into_parts(self) -> (Rhapsody, RefoundMap) {
(self.store, self.map)
}
}
impl Rhapsody {
pub fn refound(&self, moves: &Metatheses) -> Result<Refounded, UnsealedStratum> {
let recension = self.recension(moves);
self.refound_recension(&recension)
}
pub(in crate::metis) fn refound_recension(
&self,
recension: &super::recension::Recension,
) -> Result<Refounded, UnsealedStratum> {
if let Some(&dot) = recension.pending().first() {
return Err(UnsealedStratum { dot });
}
for dot in self.woven.dots() {
if !recension.is_reachable(dot) {
return Err(UnsealedStratum { dot });
}
}
let order = recension.order();
let raw_order: alloc::vec::Vec<(u32, u64)> =
order.iter().copied().map(<(u32, u64)>::from).collect();
let assignment = remint(&raw_order);
debug_assert_eq!(order.len(), assignment.minted.len());
let mut skeleton = BTreeMap::new();
let mut visible = DotSet::new();
let mut compacted = BTreeMap::new();
let mut prev: Option<((u32, u64), Locus)> = None;
for (&old, &raw_new) in order.iter().zip(&assignment.minted) {
let station = raw_new.0;
let new_dot = Dot::try_from(raw_new)
.expect("the re-mint core compacts onto the one-based range 1..=n");
let locus = match prev {
Some((prev_dot, prev_locus)) if prev_dot.0 == station => {
apply_chain_step(prev_dot, &prev_locus, 0)
}
Some((prev_dot, _)) => Locus {
anchor: Anchor::After(prev_dot.into()),
rank: base_rank(station),
},
None => Locus {
anchor: Anchor::Origin,
rank: base_rank(station),
},
};
let _ = skeleton.insert(new_dot, locus);
let _ = visible.insert(new_dot);
let _ = compacted.insert(old, new_dot);
prev = Some((raw_new, locus));
}
Ok(Refounded {
store: Self::from_parts(skeleton, visible),
map: RefoundMap {
compacted,
ceilings: self.woven.high_water(),
live: assignment.live.iter().copied().collect(),
},
})
}
}
impl super::recension::Recension {
pub(in crate::metis) fn consign_store(
&self,
map: &RefoundMap,
) -> Result<Rhapsody, UnsealedStratum> {
if let Some(&dot) = self.pending().first() {
return Err(UnsealedStratum { dot });
}
let performed = self.performed();
if let Some(&dot) = performed.unplaced.first() {
return Err(UnsealedStratum { dot });
}
let mut skeleton = BTreeMap::new();
let mut visible_set = DotSet::new();
let mut prev: Option<(Dot, Locus)> = None;
for (old, visible) in performed.thread.slots() {
let Some(new_dot) = map.translate(old) else {
continue;
};
if !visible && old.counter() > map.ceilings.get(old.station()) {
continue;
}
let locus = match prev {
Some((prev_dot, prev_locus))
if prev_dot.station() == new_dot.station()
&& prev_dot.counter().checked_add(1) == Some(new_dot.counter()) =>
{
apply_chain_step(prev_dot.into(), &prev_locus, 0)
}
Some((prev_dot, _)) => Locus {
anchor: Anchor::After(prev_dot.into()),
rank: base_rank(new_dot.station()),
},
None => Locus {
anchor: Anchor::Origin,
rank: base_rank(new_dot.station()),
},
};
let _ = skeleton.insert(new_dot, locus);
if visible {
let _ = visible_set.insert(new_dot);
}
prev = Some((new_dot, locus));
}
Ok(Rhapsody::from_parts(skeleton, visible_set))
}
}
fn base_rank(station: u32) -> Kairos {
Kairos::new(0, 0, station, 0u16)
}
#[cfg(kani)]
mod proofs {
use super::affine;
#[kani::proof]
fn the_affine_shift_is_sound_over_the_sealed_bounds() {
let live: u64 = kani::any();
let ceiling: u64 = kani::any();
let first: u64 = kani::any();
let second: u64 = kani::any();
kani::assume(live <= ceiling);
kani::assume(ceiling < first);
kani::assume(ceiling < second);
let shifted_first = affine(live, ceiling, first);
let shifted_second = affine(live, ceiling, second);
assert!(shifted_first <= first);
assert!(shifted_first > live);
if first < second {
assert!(shifted_first < shifted_second);
}
if first < u64::MAX && second == first + 1 {
assert!(shifted_second == shifted_first + 1);
}
if first != second {
assert!(shifted_first != shifted_second);
}
}
}