use std::collections::VecDeque;
pub struct SlidingWindow {
frames: VecDeque<Vec<f64>>,
capacity: usize,
}
impl SlidingWindow {
pub fn new(capacity: usize) -> Self {
Self {
frames: VecDeque::with_capacity(capacity),
capacity,
}
}
pub fn push(&mut self, frame: Vec<f64>) {
if self.frames.len() == self.capacity {
self.frames.pop_front();
}
self.frames.push_back(frame);
}
pub fn len(&self) -> usize {
self.frames.len()
}
pub fn is_empty(&self) -> bool {
self.frames.is_empty()
}
pub fn is_full(&self) -> bool {
self.frames.len() == self.capacity
}
pub fn get(&self, index: usize) -> &[f64] {
&self.frames[index]
}
pub fn latest(&self) -> Option<&[f64]> {
self.frames.back().map(|v| v.as_slice())
}
pub fn iter(&self) -> impl Iterator<Item = &[f64]> {
self.frames.iter().map(|v| v.as_slice())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_window() {
let w = SlidingWindow::new(3);
assert_eq!(w.len(), 0);
assert!(w.is_empty());
assert!(!w.is_full());
assert_eq!(w.latest(), None);
assert_eq!(w.iter().count(), 0);
}
#[test]
fn push_within_capacity() {
let mut w = SlidingWindow::new(3);
w.push(vec![1.0, 2.0]);
w.push(vec![3.0, 4.0]);
assert_eq!(w.len(), 2);
assert!(!w.is_full());
assert_eq!(w.get(0), &[1.0, 2.0]);
assert_eq!(w.get(1), &[3.0, 4.0]);
assert_eq!(w.latest(), Some([3.0, 4.0].as_slice()));
}
#[test]
fn push_at_capacity() {
let mut w = SlidingWindow::new(3);
w.push(vec![1.0]);
w.push(vec![2.0]);
w.push(vec![3.0]);
assert!(w.is_full());
assert_eq!(w.len(), 3);
assert_eq!(w.get(0), &[1.0]);
assert_eq!(w.get(2), &[3.0]);
}
#[test]
fn push_beyond_capacity_drops_oldest() {
let mut w = SlidingWindow::new(3);
w.push(vec![1.0]);
w.push(vec![2.0]);
w.push(vec![3.0]);
w.push(vec![4.0]);
assert!(w.is_full());
assert_eq!(w.len(), 3);
assert_eq!(w.get(0), &[2.0]); assert_eq!(w.get(1), &[3.0]);
assert_eq!(w.get(2), &[4.0]);
assert_eq!(w.latest(), Some([4.0].as_slice()));
}
#[test]
fn is_full_transitions() {
let mut w = SlidingWindow::new(2);
assert!(!w.is_full());
w.push(vec![1.0]);
assert!(!w.is_full());
w.push(vec![2.0]);
assert!(w.is_full());
w.push(vec![3.0]); assert!(w.is_full());
}
#[test]
fn iter_oldest_to_newest() {
let mut w = SlidingWindow::new(3);
w.push(vec![10.0]);
w.push(vec![20.0]);
w.push(vec![30.0]);
let collected: Vec<&[f64]> = w.iter().collect();
assert_eq!(collected, vec![[10.0].as_slice(), &[20.0], &[30.0]]);
}
#[test]
fn iter_after_overflow() {
let mut w = SlidingWindow::new(2);
w.push(vec![1.0]);
w.push(vec![2.0]);
w.push(vec![3.0]);
w.push(vec![4.0]);
let collected: Vec<&[f64]> = w.iter().collect();
assert_eq!(collected, vec![[3.0].as_slice(), &[4.0]]);
}
#[test]
fn variable_frame_sizes() {
let mut w = SlidingWindow::new(3);
w.push(vec![1.0, 2.0]);
w.push(vec![3.0, 4.0, 5.0]);
w.push(vec![6.0]);
assert_eq!(w.get(0), &[1.0, 2.0]);
assert_eq!(w.get(1), &[3.0, 4.0, 5.0]);
assert_eq!(w.get(2), &[6.0]);
}
}