use crate::header::Counter;
pub trait FrameCounter {
fn next(&mut self) -> Counter;
}
#[derive(Copy, Clone, Debug)]
pub struct MonotonicCounter {
current_counter: u64,
max_counter: u64,
exhausted: bool,
}
impl MonotonicCounter {
pub fn new(max_counter: u64) -> Self {
Self::with_start_value(0, max_counter)
}
pub fn with_start_value(start_value: u64, max_counter: u64) -> Self {
Self {
current_counter: start_value,
max_counter,
exhausted: false,
}
}
pub fn current(&self) -> Counter {
self.current_counter
}
pub fn is_exhausted(&self) -> bool {
self.exhausted
}
}
impl FrameCounter for MonotonicCounter {
fn next(&mut self) -> Counter {
assert!(
!self.exhausted,
"MonotonicCounter is exhausted, its maximum value {} was already used",
self.max_counter
);
let counter = self.current_counter;
if counter >= self.max_counter {
self.exhausted = true;
} else {
self.current_counter += 1;
}
counter
}
}
impl Default for MonotonicCounter {
fn default() -> Self {
Self::new(u64::MAX)
}
}
#[cfg(test)]
mod test {
use crate::frame::FrameCounter;
use super::MonotonicCounter;
use pretty_assertions::assert_eq;
#[test]
fn create_increasing_counters() {
let mut counter = MonotonicCounter::default();
for i in 0..10 {
assert_eq!(counter.next(), i);
}
}
#[test]
fn is_exhausted_after_max_counter_was_returned() {
let mut counter = MonotonicCounter::new(1);
assert_eq!(counter.next(), 0);
assert!(!counter.is_exhausted());
assert_eq!(counter.next(), 1);
assert!(counter.is_exhausted());
}
#[test]
#[should_panic(expected = "exhausted")]
fn panics_when_exhausted() {
let mut counter = MonotonicCounter::new(1);
counter.next();
counter.next();
counter.next();
}
#[test]
#[should_panic(expected = "exhausted")]
fn panics_when_u64_max_was_reached() {
let mut counter = MonotonicCounter::with_start_value(u64::MAX - 1, u64::MAX);
assert_eq!(counter.next(), u64::MAX - 1);
assert_eq!(counter.next(), u64::MAX);
assert!(counter.is_exhausted());
counter.next();
}
}