use crate::view_state::{ViewEpoch, ViewState, ViewVersion};
#[derive(Clone, Debug)]
pub struct ViewBoundContext<T> {
pub data: T,
pub bound_at: ViewVersion,
pub bound_epoch: ViewEpoch,
}
impl<T> ViewBoundContext<T> {
#[must_use]
pub fn bind(data: T, view: &ViewState) -> Self {
Self {
data,
bound_at: view.version,
bound_epoch: view.epoch,
}
}
#[must_use]
pub fn validity(&self, current: &ViewState) -> BoundContextValidity {
if current.version == self.bound_at {
BoundContextValidity::Current
} else if current.epoch == self.bound_epoch {
BoundContextValidity::StaleWithinEpoch {
versions_behind: current.version.versions_since(self.bound_at),
}
} else {
BoundContextValidity::InvalidAcrossEpoch {
epochs_behind: current
.epoch
.as_u64()
.saturating_sub(self.bound_epoch.as_u64()),
}
}
}
pub fn rebind(&mut self, view: &ViewState) {
self.bound_at = view.version;
self.bound_epoch = view.epoch;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BoundContextValidity {
Current,
StaleWithinEpoch {
versions_behind: u64,
},
InvalidAcrossEpoch {
epochs_behind: u64,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn current_when_same_version() {
let view = ViewState::fixed_initial();
let bound = ViewBoundContext::bind(42u32, &view);
assert_eq!(bound.validity(&view), BoundContextValidity::Current);
}
#[test]
fn stale_within_epoch() {
let view = ViewState::fixed_initial();
let bound = ViewBoundContext::bind(42u32, &view);
let mut updated = view.clone();
updated.version = ViewVersion::new(5);
assert_eq!(
bound.validity(&updated),
BoundContextValidity::StaleWithinEpoch { versions_behind: 5 }
);
}
#[test]
fn invalid_across_epoch() {
let view = ViewState::fixed_initial();
let bound = ViewBoundContext::bind(42u32, &view);
let mut updated = view.clone();
updated.epoch = ViewEpoch::new(3);
updated.version = ViewVersion::new(10);
assert_eq!(
bound.validity(&updated),
BoundContextValidity::InvalidAcrossEpoch { epochs_behind: 3 }
);
}
#[test]
fn rebind_resets_validity() {
let view = ViewState::fixed_initial();
let mut bound = ViewBoundContext::bind(42u32, &view);
let mut updated = view.clone();
updated.version = ViewVersion::new(5);
bound.rebind(&updated);
assert_eq!(bound.validity(&updated), BoundContextValidity::Current);
}
}