#[derive(Debug, Clone)]
pub struct CircularTimestamps {
buf: Vec<i64>,
head: usize,
len: usize,
}
impl CircularTimestamps {
pub fn new(capacity: usize) -> Self {
Self {
buf: vec![0; capacity],
head: 0,
len: 0,
}
}
pub fn push(&mut self, ts: i64) {
let cap = self.buf.len();
if cap == 0 {
return;
}
let write_pos = if self.len < cap {
self.len
} else {
let pos = self.head;
self.head = (self.head + 1) % cap;
pos
};
if let Some(slot) = self.buf.get_mut(write_pos) {
*slot = ts;
}
if self.len < cap {
self.len += 1;
}
}
pub fn is_full(&self) -> bool {
self.len == self.buf.len()
}
pub fn oldest(&self) -> Option<i64> {
if self.len == 0 {
return None;
}
self.buf.get(self.head).copied()
}
pub fn newest(&self) -> Option<i64> {
if self.len == 0 {
return None;
}
let cap = self.buf.len();
let idx = if self.len < cap {
self.len - 1
} else {
(self.head + cap - 1) % cap
};
self.buf.get(idx).copied()
}
pub fn threshold_reached(&self, find_time: i64) -> bool {
if !self.is_full() {
return false;
}
match (self.oldest(), self.newest()) {
(Some(old), Some(new)) => (new - old) < find_time,
_ => false,
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.buf.len()
}
}
#[cfg(test)]
mod tests {
use crate::track::circular::CircularTimestamps;
#[test]
fn empty_buffer() {
let buf = CircularTimestamps::new(3);
assert!(buf.is_empty());
assert!(!buf.is_full());
assert_eq!(buf.len(), 0);
assert_eq!(buf.oldest(), None);
assert_eq!(buf.newest(), None);
assert!(!buf.threshold_reached(600));
}
#[test]
fn push_until_full() {
let mut buf = CircularTimestamps::new(3);
buf.push(100);
assert_eq!(buf.len(), 1);
assert_eq!(buf.oldest(), Some(100));
assert_eq!(buf.newest(), Some(100));
buf.push(200);
buf.push(300);
assert!(buf.is_full());
assert_eq!(buf.oldest(), Some(100));
assert_eq!(buf.newest(), Some(300));
}
#[test]
fn overwrites_oldest_when_full() {
let mut buf = CircularTimestamps::new(3);
buf.push(100);
buf.push(200);
buf.push(300);
buf.push(400);
assert!(buf.is_full());
assert_eq!(buf.oldest(), Some(200));
assert_eq!(buf.newest(), Some(400));
buf.push(500);
assert_eq!(buf.oldest(), Some(300));
assert_eq!(buf.newest(), Some(500));
}
#[test]
fn threshold_within_window() {
let mut buf = CircularTimestamps::new(5);
for i in 0..5 {
buf.push(1000 + i * 10);
}
assert!(buf.threshold_reached(600)); assert!(buf.threshold_reached(50)); assert!(!buf.threshold_reached(30)); }
#[test]
fn threshold_not_full() {
let mut buf = CircularTimestamps::new(5);
buf.push(1000);
buf.push(1001);
assert!(!buf.threshold_reached(600));
}
#[test]
fn threshold_after_wrap() {
let mut buf = CircularTimestamps::new(3);
buf.push(100);
buf.push(200);
buf.push(300);
buf.push(1000);
buf.push(1001);
assert_eq!(buf.oldest(), Some(300));
assert!(buf.threshold_reached(800)); assert!(!buf.threshold_reached(600)); }
#[test]
fn zero_capacity() {
let mut buf = CircularTimestamps::new(0);
buf.push(100); assert!(buf.is_empty());
assert_eq!(buf.capacity(), 0);
}
#[test]
fn capacity_one() {
let mut buf = CircularTimestamps::new(1);
buf.push(100);
assert!(buf.is_full());
assert_eq!(buf.oldest(), Some(100));
assert_eq!(buf.newest(), Some(100));
assert!(buf.threshold_reached(1));
buf.push(200);
assert_eq!(buf.oldest(), Some(200));
assert_eq!(buf.newest(), Some(200));
}
#[test]
fn negative_timestamps() {
let mut buf = CircularTimestamps::new(3);
buf.push(-100);
buf.push(-50);
buf.push(-10);
assert!(buf.is_full());
assert_eq!(buf.oldest(), Some(-100));
assert_eq!(buf.newest(), Some(-10));
assert!(buf.threshold_reached(200));
assert!(!buf.threshold_reached(50));
}
#[test]
fn threshold_with_find_time_zero() {
let mut buf = CircularTimestamps::new(3);
buf.push(100);
buf.push(100);
buf.push(100);
assert!(!buf.threshold_reached(0));
}
#[test]
fn len_and_is_empty_through_lifecycle() {
let mut buf = CircularTimestamps::new(2);
assert!(buf.is_empty());
assert_eq!(buf.len(), 0);
buf.push(1);
assert!(!buf.is_empty());
assert_eq!(buf.len(), 1);
buf.push(2);
assert_eq!(buf.len(), 2);
buf.push(3);
assert_eq!(buf.len(), 2);
assert!(!buf.is_empty());
}
#[test]
fn capacity_returns_correct_value() {
let buf = CircularTimestamps::new(42);
assert_eq!(buf.capacity(), 42);
}
}