use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug, Default)]
struct ScanProgressInner {
scanned_to: AtomicU64,
observed_tip: AtomicU64,
}
#[derive(Clone, Debug, Default)]
pub struct ScanProgress(Arc<ScanProgressInner>);
impl ScanProgress {
pub fn scanned_to(&self) -> Option<u64> {
match self.0.scanned_to.load(Ordering::Relaxed) {
0 => None,
block => Some(block),
}
}
pub fn observed_tip(&self) -> Option<u64> {
match self.0.observed_tip.load(Ordering::Relaxed) {
0 => None,
block => Some(block),
}
}
pub(crate) fn record_scanned_to(&self, block: u64) {
self.0.scanned_to.fetch_max(block, Ordering::Relaxed);
}
pub(crate) fn record_observed_tip(&self, block: u64) {
self.0.observed_tip.fetch_max(block, Ordering::Relaxed);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unset_before_any_observation() {
let progress = ScanProgress::default();
assert_eq!(progress.scanned_to(), None);
assert_eq!(progress.observed_tip(), None);
}
#[test]
fn record_scanned_to_never_moves_backwards() {
let progress = ScanProgress::default();
progress.record_scanned_to(100);
assert_eq!(progress.scanned_to(), Some(100));
progress.record_scanned_to(50);
assert_eq!(
progress.scanned_to(),
Some(100),
"a lower block recorded after a higher one must not move progress backwards"
);
progress.record_scanned_to(150);
assert_eq!(progress.scanned_to(), Some(150));
}
#[test]
fn record_observed_tip_never_moves_backwards() {
let progress = ScanProgress::default();
progress.record_observed_tip(100);
progress.record_observed_tip(50);
assert_eq!(
progress.observed_tip(),
Some(100),
"a lower tip recorded after a higher one must not move progress backwards"
);
}
}