use crate::UserKey;
use crate::comparator::UserComparator;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::cmp::Ordering;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Boundary {
pub key: UserKey,
pub after: Vec<(UserKey, u64)>,
}
impl Boundary {
pub fn reached_bytes(&self, last: &[u8], comparator: &dyn UserComparator) -> u64 {
self.after
.iter()
.take_while(|(min, _)| comparator.compare(min, last) != Ordering::Greater)
.map(|&(_, bytes)| bytes)
.sum()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) struct Crossing {
pub(super) passed: usize,
pub(super) counted: u32,
}
#[derive(Clone, Debug)]
pub(super) struct CutAlignment {
boundaries: Arc<[Boundary]>,
next: usize,
crossed: u32,
started: bool,
upper: Option<UserKey>,
}
impl CutAlignment {
pub(super) fn new(boundaries: Arc<[Boundary]>, upper: Option<UserKey>) -> Self {
Self {
boundaries,
next: 0,
crossed: 0,
started: false,
upper,
}
}
pub(super) fn limit(&mut self, upper: UserKey) {
self.upper = Some(upper);
}
pub(super) fn crossing(&self, key: &[u8], comparator: &dyn UserComparator) -> Crossing {
let passed = self
.boundaries
.get(self.next..)
.unwrap_or_default()
.iter()
.take_while(|boundary| comparator.compare(&boundary.key, key) == Ordering::Less)
.count();
let counted = if self.started {
u32::try_from(passed).unwrap_or(u32::MAX)
} else {
0
};
Crossing { passed, counted }
}
pub(super) fn commit(&mut self, crossing: Crossing, cut: bool) {
self.next += crossing.passed;
self.started = true;
self.crossed = if cut {
0
} else {
self.crossed + crossing.counted
};
}
pub(super) fn floor_percent(&self, crossing: Crossing) -> u64 {
let n = self.crossed + crossing.counted;
50 + 5 * u64::from(n.clamp(1, 9) - 1)
}
pub(super) fn ahead(&self, crossing: Crossing, comparator: &dyn UserComparator) -> bool {
self.boundaries
.get(self.next + crossing.passed)
.is_some_and(|boundary| {
self.upper
.as_ref()
.is_none_or(|upper| comparator.compare(&boundary.key, upper) == Ordering::Less)
})
}
pub(super) fn inside(
&self,
crossing: Crossing,
last: &[u8],
comparator: &dyn UserComparator,
) -> Option<&Boundary> {
self.boundaries
.get(self.next + crossing.passed)
.filter(|boundary| comparator.compare(&boundary.key, last) == Ordering::Less)
}
pub(super) fn pass_through(
&mut self,
last: &[u8],
past_half: bool,
comparator: &dyn UserComparator,
) {
let mut crossing = self.crossing(last, comparator);
if !past_half {
crossing.counted = 0;
}
self.commit(crossing, false);
}
}
pub(super) fn share_of(target: u64, percent: u64) -> u64 {
u64::try_from(u128::from(target) * u128::from(percent) / 100).unwrap_or(u64::MAX)
}
#[cfg(test)]
mod tests;