extern crate alloc;
use alloc::collections::{BTreeMap, BTreeSet};
use core::num::NonZeroU64;
use super::{Cut, Dot, VersionVector};
mod algebra;
mod reads;
mod station;
mod wire;
pub(in crate::metis) use wire::{HAVE_SET_STATION_LEN, HAVE_SET_WIRE_HEADER_LEN};
pub use wire::{HaveSetDecodeBudget, HaveSetDecodeError};
use station::StationDots;
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct DotSet {
pub(in crate::metis::dot_set) stations: BTreeMap<u32, StationDots>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DotSetStation {
station: u32,
floor: u64,
high_water: u64,
}
impl DotSetStation {
#[must_use]
pub const fn station(self) -> u32 {
self.station
}
#[must_use]
pub const fn floor(self) -> u64 {
self.floor
}
#[must_use]
pub const fn high_water(self) -> u64 {
self.high_water
}
#[must_use]
pub const fn forward_gap(self) -> u64 {
self.high_water.saturating_sub(self.floor)
}
}
impl DotSet {
#[must_use]
pub const fn new() -> Self {
Self {
stations: BTreeMap::new(),
}
}
#[must_use]
pub fn from_witnessed(cut: &Cut) -> Self {
Self::from_cut(cut.as_vector())
}
#[must_use]
pub(crate) fn from_cut(cut: &VersionVector) -> Self {
Self {
stations: cut
.iter()
.map(|(station, count)| {
(
station,
StationDots {
floor: count,
above: BTreeSet::new(),
},
)
})
.collect(),
}
}
pub fn insert(&mut self, dot: Dot) -> bool {
let counter = dot.counter();
let slot = self.stations.entry(dot.station()).or_default();
if slot.contains(counter) {
return false;
}
if counter == slot.floor.saturating_add(1) {
slot.floor = counter;
slot.absorb();
} else {
let _ = slot.above.insert(counter);
}
true
}
pub(crate) fn insert_run(&mut self, station: u32, first: NonZeroU64, len: u32) {
if len == 0 {
return;
}
let start = first.get();
let last = start.saturating_add(u64::from(len) - 1);
let slot = self.stations.entry(station).or_default();
if start <= slot.floor.saturating_add(1) {
if last > slot.floor {
slot.floor = last;
match slot.floor.checked_add(1) {
Some(next) => slot.above = slot.above.split_off(&next),
None => slot.above.clear(),
}
slot.absorb();
}
} else {
slot.above.extend(start..=last);
}
}
pub(crate) fn remove(&mut self, dot: Dot) -> bool {
let station = dot.station();
let Some(slot) = self.stations.get_mut(&station) else {
return false;
};
let removed = slot.remove(dot.counter());
if slot.floor == 0 && slot.above.is_empty() {
let _ = self.stations.remove(&station);
}
removed
}
#[must_use]
pub fn contains(&self, dot: Dot) -> bool {
self.stations
.get(&dot.station())
.is_some_and(|slot| slot.contains(dot.counter()))
}
#[must_use]
pub fn floor(&self) -> VersionVector {
let mut cut = VersionVector::new();
for (&station, slot) in &self.stations {
cut.observe(station, slot.floor);
}
cut
}
#[must_use]
pub fn high_water(&self) -> VersionVector {
let mut bound = VersionVector::new();
for (&station, slot) in &self.stations {
bound.observe(station, slot.high_water());
}
bound
}
}