pine_core/
series_buffer.rs1use std::collections::VecDeque;
7
8pub const MAX_LOOKBACK: usize = 5000;
11
12#[derive(Debug, Clone)]
14pub struct SeriesBuffer<T> {
15 values: VecDeque<T>,
17}
18
19impl<T> Default for SeriesBuffer<T> {
20 fn default() -> Self {
21 Self {
22 values: VecDeque::new(),
23 }
24 }
25}
26
27impl<T> SeriesBuffer<T> {
28 pub fn push(&mut self, value: T, capacity: usize) {
30 self.values.push_front(value);
31 let capacity = capacity.clamp(1, MAX_LOOKBACK);
32 while self.values.len() > capacity {
33 self.values.pop_back();
34 }
35 }
36
37 pub fn get(&self, offset: usize) -> Option<&T> {
40 self.values.get(offset)
41 }
42
43 pub fn len(&self) -> usize {
45 self.values.len()
46 }
47
48 pub fn is_empty(&self) -> bool {
49 self.values.is_empty()
50 }
51
52 pub fn iter(&self) -> impl Iterator<Item = &T> {
54 self.values.iter()
55 }
56}
57
58impl SeriesBuffer<f64> {
59 pub fn window(&self, n: usize) -> Vec<f64> {
61 self.values.iter().take(n).copied().collect()
62 }
63
64 pub fn observe(&mut self, value: f64, length: usize) -> Option<Vec<f64>> {
70 self.push(value, length);
71 (self.len() >= length).then(|| self.window(length))
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn keeps_newest_values_up_to_capacity() {
81 let mut buf = SeriesBuffer::default();
82 for value in [1.0, 2.0, 3.0, 4.0] {
83 buf.push(value, 3);
84 }
85
86 assert_eq!(buf.len(), 3);
87 assert_eq!(buf.window(3), vec![4.0, 3.0, 2.0]);
88 assert_eq!(buf.get(0), Some(&4.0));
89 assert_eq!(buf.get(2), Some(&2.0));
90 assert_eq!(buf.get(3), None);
91 }
92
93 #[test]
94 fn window_is_short_while_warming_up() {
95 let mut buf = SeriesBuffer::default();
96 buf.push(1.0, 5);
97 buf.push(2.0, 5);
98
99 assert_eq!(buf.window(5), vec![2.0, 1.0]);
100 }
101
102 #[test]
103 fn observe_withholds_a_window_until_it_fills() {
104 let mut buf = SeriesBuffer::default();
105
106 assert_eq!(buf.observe(1.0, 3), None);
107 assert_eq!(buf.observe(2.0, 3), None);
108 assert_eq!(buf.observe(3.0, 3), Some(vec![3.0, 2.0, 1.0]));
109 assert_eq!(buf.observe(4.0, 3), Some(vec![4.0, 3.0, 2.0]));
110 }
111
112 #[test]
113 fn capacity_is_bounded_by_max_lookback() {
114 let mut buf = SeriesBuffer::default();
115 for value in 0..(MAX_LOOKBACK + 10) {
116 buf.push(value as f64, usize::MAX);
117 }
118
119 assert_eq!(buf.len(), MAX_LOOKBACK);
120 }
121}