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