1use crate::error::{SpotError, SpotResult};
8
9#[derive(Debug, Clone)]
11pub struct Ubend {
12 cursor: usize,
14 capacity: usize,
16 last_erased_data: f64,
18 filled: bool,
20 data: Vec<f64>,
22}
23
24impl Ubend {
25 pub fn new(capacity: usize) -> SpotResult<Self> {
27 if capacity == 0 {
28 return Err(SpotError::MemoryAllocationFailed);
29 }
30
31 Ok(Self {
32 cursor: 0,
33 filled: false,
34 capacity,
35 last_erased_data: f64::NAN,
36 data: vec![0.0; capacity],
37 })
38 }
39
40 pub fn size(&self) -> usize {
43 if self.filled {
44 self.capacity
45 } else {
46 self.cursor
47 }
48 }
49
50 pub fn push(&mut self, x: f64) -> f64 {
53 if self.filled {
56 self.last_erased_data = self.data[self.cursor];
57 }
58
59 self.data[self.cursor] = x;
61
62 if self.cursor == self.capacity - 1 {
64 self.cursor = 0;
65 self.filled = true;
66 } else {
67 self.cursor += 1;
68 }
69
70 self.last_erased_data
71 }
72
73 pub fn iter(&self) -> UbendIterator<'_> {
75 UbendIterator {
76 ubend: self,
77 index: 0,
78 }
79 }
80
81 pub fn get(&self, index: usize) -> Option<f64> {
83 let size = self.size();
84 if index >= size {
85 return None;
86 }
87
88 if !self.filled {
89 Some(self.data[index])
91 } else {
92 let real_index = (self.cursor + index) % self.capacity;
94 Some(self.data[real_index])
95 }
96 }
97
98 pub fn raw_data(&self) -> &[f64] {
100 &self.data
101 }
102
103 pub fn capacity(&self) -> usize {
105 self.capacity
106 }
107
108 pub fn is_filled(&self) -> bool {
110 self.filled
111 }
112
113 pub fn cursor(&self) -> usize {
115 self.cursor
116 }
117
118 pub fn last_erased_data(&self) -> f64 {
120 self.last_erased_data
121 }
122
123 pub fn data(&self) -> Vec<f64> {
125 self.iter().collect()
126 }
127}
128
129pub struct UbendIterator<'a> {
131 ubend: &'a Ubend,
132 index: usize,
133}
134
135impl<'a> Iterator for UbendIterator<'a> {
136 type Item = f64;
137
138 fn next(&mut self) -> Option<Self::Item> {
139 let result = self.ubend.get(self.index);
140 self.index += 1;
141 result
142 }
143}
144
145impl<'a> ExactSizeIterator for UbendIterator<'a> {
146 fn len(&self) -> usize {
147 self.ubend.size()
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use approx::assert_relative_eq;
155
156 #[test]
157 fn test_ubend_creation() {
158 let ubend = Ubend::new(5).unwrap();
159 assert_eq!(ubend.capacity(), 5);
160 assert_eq!(ubend.size(), 0);
161 assert!(!ubend.is_filled());
162 assert_eq!(ubend.cursor(), 0);
163 assert!(ubend.last_erased_data().is_nan());
164 }
165
166 #[test]
167 fn test_ubend_zero_capacity() {
168 let result = Ubend::new(0);
169 assert!(result.is_err());
170 assert_eq!(result.unwrap_err(), SpotError::MemoryAllocationFailed);
171 }
172
173 #[test]
174 fn test_ubend_push_before_full() {
175 let mut ubend = Ubend::new(3).unwrap();
176
177 let erased = ubend.push(1.0);
179 assert!(erased.is_nan());
180 assert_eq!(ubend.size(), 1);
181 assert!(!ubend.is_filled());
182 assert_eq!(ubend.cursor(), 1);
183
184 let erased = ubend.push(2.0);
186 assert!(erased.is_nan());
187 assert_eq!(ubend.size(), 2);
188 assert!(!ubend.is_filled());
189 assert_eq!(ubend.cursor(), 2);
190
191 let erased = ubend.push(3.0);
193 assert!(erased.is_nan());
194 assert_eq!(ubend.size(), 3);
195 assert!(ubend.is_filled());
196 assert_eq!(ubend.cursor(), 0);
197 }
198
199 #[test]
200 fn test_ubend_push_after_full() {
201 let mut ubend = Ubend::new(3).unwrap();
202
203 ubend.push(1.0);
205 ubend.push(2.0);
206 ubend.push(3.0);
207
208 let erased = ubend.push(4.0);
210 assert_relative_eq!(erased, 1.0);
211 assert_eq!(ubend.size(), 3);
212 assert!(ubend.is_filled());
213 assert_eq!(ubend.cursor(), 1);
214
215 let erased = ubend.push(5.0);
216 assert_relative_eq!(erased, 2.0);
217 assert_eq!(ubend.size(), 3);
218 assert!(ubend.is_filled());
219 assert_eq!(ubend.cursor(), 2);
220 }
221
222 #[test]
223 fn test_ubend_get() {
224 let mut ubend = Ubend::new(3).unwrap();
225
226 assert!(ubend.get(0).is_none());
228
229 ubend.push(10.0);
231 ubend.push(20.0);
232
233 assert_relative_eq!(ubend.get(0).unwrap(), 10.0);
234 assert_relative_eq!(ubend.get(1).unwrap(), 20.0);
235 assert!(ubend.get(2).is_none());
236
237 ubend.push(30.0);
239 ubend.push(40.0); assert_relative_eq!(ubend.get(0).unwrap(), 20.0);
242 assert_relative_eq!(ubend.get(1).unwrap(), 30.0);
243 assert_relative_eq!(ubend.get(2).unwrap(), 40.0);
244 }
245
246 #[test]
247 fn test_ubend_iterator() {
248 let mut ubend = Ubend::new(3).unwrap();
249
250 ubend.push(1.0);
251 ubend.push(2.0);
252 ubend.push(3.0);
253
254 let values: Vec<f64> = ubend.iter().collect();
255 assert_eq!(values, vec![1.0, 2.0, 3.0]);
256
257 ubend.push(4.0);
259 let values: Vec<f64> = ubend.iter().collect();
260 assert_eq!(values, vec![2.0, 3.0, 4.0]);
261 }
262
263 #[test]
264 fn test_ubend_exact_size_iterator() {
265 let mut ubend = Ubend::new(3).unwrap();
266
267 assert_eq!(ubend.iter().len(), 0);
268
269 ubend.push(1.0);
270 assert_eq!(ubend.iter().len(), 1);
271
272 ubend.push(2.0);
273 ubend.push(3.0);
274 assert_eq!(ubend.iter().len(), 3);
275
276 ubend.push(4.0);
277 assert_eq!(ubend.iter().len(), 3);
278 }
279}