1#![forbid(unsafe_code)]
2
3use std::collections::VecDeque;
27use std::ops::Range;
28
29#[derive(Debug, Clone)]
34pub struct LogRing<T> {
35 ring: VecDeque<T>,
37
38 capacity: usize,
40
41 total_count: usize,
43}
44
45impl<T> LogRing<T> {
46 #[must_use]
52 pub fn new(capacity: usize) -> Self {
53 assert!(capacity > 0, "LogRing capacity must be greater than 0");
54 Self {
55 ring: VecDeque::with_capacity(capacity),
56 capacity,
57 total_count: 0,
58 }
59 }
60
61 pub fn push(&mut self, item: T) {
65 self.total_count = self.total_count.saturating_add(1);
66
67 if self.ring.len() >= self.capacity {
68 self.ring.pop_front();
69 }
70
71 self.ring.push_back(item);
72 }
73
74 pub fn extend(&mut self, items: impl IntoIterator<Item = T>) {
76 for item in items {
77 self.push(item);
78 }
79 }
80
81 #[must_use]
85 pub fn get(&self, absolute_idx: usize) -> Option<&T> {
86 let ring_start = self.first_index();
87
88 if absolute_idx >= ring_start && absolute_idx < self.total_count {
89 self.ring.get(absolute_idx - ring_start)
90 } else {
91 None
92 }
93 }
94
95 #[must_use]
97 pub fn get_mut(&mut self, absolute_idx: usize) -> Option<&mut T> {
98 let ring_start = self.first_index();
99
100 if absolute_idx >= ring_start && absolute_idx < self.total_count {
101 self.ring.get_mut(absolute_idx - ring_start)
102 } else {
103 None
104 }
105 }
106
107 pub fn get_range(&self, range: Range<usize>) -> impl Iterator<Item = &T> {
112 let ring_start = self.first_index();
113 let ring_end = self.total_count;
114
115 let start = range.start.max(ring_start);
117 let end = range.end.min(ring_end);
118
119 (start..end).filter_map(move |i| self.get(i))
120 }
121
122 #[must_use]
124 pub const fn total_count(&self) -> usize {
125 self.total_count
126 }
127
128 #[must_use]
130 pub fn len(&self) -> usize {
131 self.ring.len()
132 }
133
134 #[must_use]
136 pub fn is_empty(&self) -> bool {
137 self.ring.is_empty()
138 }
139
140 #[must_use]
142 pub const fn capacity(&self) -> usize {
143 self.capacity
144 }
145
146 #[must_use]
148 pub fn first_index(&self) -> usize {
149 self.total_count.saturating_sub(self.ring.len())
150 }
151
152 #[must_use]
156 pub fn last_index(&self) -> Option<usize> {
157 if self.total_count > 0 {
158 Some(self.total_count - 1)
159 } else {
160 None
161 }
162 }
163
164 #[must_use]
166 pub fn is_in_memory(&self, absolute_idx: usize) -> bool {
167 absolute_idx >= self.first_index() && absolute_idx < self.total_count
168 }
169
170 #[must_use]
172 pub fn evicted_count(&self) -> usize {
173 self.first_index()
174 }
175
176 pub fn clear(&mut self) {
180 self.ring.clear();
181 }
182
183 pub fn reset(&mut self) {
185 self.ring.clear();
186 self.total_count = 0;
187 }
188
189 #[must_use]
191 pub fn back(&self) -> Option<&T> {
192 self.ring.back()
193 }
194
195 #[must_use]
197 pub fn front(&self) -> Option<&T> {
198 self.ring.front()
199 }
200
201 pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> {
203 self.ring.iter()
204 }
205
206 pub fn iter_indexed(&self) -> impl DoubleEndedIterator<Item = (usize, &T)> {
208 let start = self.first_index();
209 self.ring
210 .iter()
211 .enumerate()
212 .map(move |(i, item)| (start + i, item))
213 }
214
215 pub fn drain(&mut self) -> impl Iterator<Item = T> + '_ {
217 self.ring.drain(..)
218 }
219}
220
221impl<T> Default for LogRing<T> {
222 fn default() -> Self {
223 Self::new(1024) }
225}
226
227impl<T> Extend<T> for LogRing<T> {
228 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
229 for item in iter {
230 self.push(item);
231 }
232 }
233}
234
235impl<T> FromIterator<T> for LogRing<T> {
236 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
237 let items: Vec<T> = iter.into_iter().collect();
238 let capacity = items.len().max(1);
239 let mut ring = Self::new(capacity);
240 ring.extend(items);
241 ring
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn new_creates_empty_ring() {
251 let ring: LogRing<i32> = LogRing::new(10);
252 assert!(ring.is_empty());
253 assert_eq!(ring.len(), 0);
254 assert_eq!(ring.total_count(), 0);
255 assert_eq!(ring.capacity(), 10);
256 }
257
258 #[test]
259 #[should_panic(expected = "capacity must be greater than 0")]
260 fn new_panics_on_zero_capacity() {
261 let _ring: LogRing<i32> = LogRing::new(0);
262 }
263
264 #[test]
265 fn push_adds_items() {
266 let mut ring = LogRing::new(5);
267 ring.push("a");
268 ring.push("b");
269 ring.push("c");
270
271 assert_eq!(ring.len(), 3);
272 assert_eq!(ring.total_count(), 3);
273 assert_eq!(ring.get(0), Some(&"a"));
274 assert_eq!(ring.get(1), Some(&"b"));
275 assert_eq!(ring.get(2), Some(&"c"));
276 }
277
278 #[test]
279 fn push_evicts_oldest_when_full() {
280 let mut ring = LogRing::new(3);
281 ring.push(1);
282 ring.push(2);
283 ring.push(3);
284 ring.push(4); ring.push(5); assert_eq!(ring.len(), 3);
288 assert_eq!(ring.total_count(), 5);
289 assert_eq!(ring.get(0), None); assert_eq!(ring.get(1), None); assert_eq!(ring.get(2), Some(&3));
292 assert_eq!(ring.get(3), Some(&4));
293 assert_eq!(ring.get(4), Some(&5));
294 }
295
296 #[test]
297 fn first_and_last_index() {
298 let mut ring = LogRing::new(3);
299 assert_eq!(ring.first_index(), 0);
300 assert_eq!(ring.last_index(), None);
301
302 ring.push("a");
303 ring.push("b");
304 assert_eq!(ring.first_index(), 0);
305 assert_eq!(ring.last_index(), Some(1));
306
307 ring.push("c");
308 ring.push("d"); assert_eq!(ring.first_index(), 1);
310 assert_eq!(ring.last_index(), Some(3));
311 }
312
313 #[test]
314 fn get_range_returns_available_items() {
315 let mut ring = LogRing::new(3);
316 ring.push("a");
317 ring.push("b");
318 ring.push("c");
319 ring.push("d"); let items: Vec<_> = ring.get_range(0..5).collect();
322 assert_eq!(items, vec![&"b", &"c", &"d"]);
323
324 let items: Vec<_> = ring.get_range(2..4).collect();
325 assert_eq!(items, vec![&"c", &"d"]);
326 }
327
328 #[test]
329 fn is_in_memory() {
330 let mut ring = LogRing::new(2);
331 ring.push(1);
332 ring.push(2);
333 ring.push(3); assert!(!ring.is_in_memory(0));
336 assert!(ring.is_in_memory(1));
337 assert!(ring.is_in_memory(2));
338 assert!(!ring.is_in_memory(3));
339 }
340
341 #[test]
342 fn evicted_count() {
343 let mut ring = LogRing::new(2);
344 assert_eq!(ring.evicted_count(), 0);
345
346 ring.push(1);
347 ring.push(2);
348 assert_eq!(ring.evicted_count(), 0);
349
350 ring.push(3); assert_eq!(ring.evicted_count(), 1);
352
353 ring.push(4); assert_eq!(ring.evicted_count(), 2);
355 }
356
357 #[test]
358 fn clear_preserves_total_count() {
359 let mut ring = LogRing::new(5);
360 ring.push(1);
361 ring.push(2);
362 ring.push(3);
363
364 ring.clear();
365 assert!(ring.is_empty());
366 assert_eq!(ring.total_count(), 3);
367 assert_eq!(ring.first_index(), 3);
368 }
369
370 #[test]
371 fn reset_clears_everything() {
372 let mut ring = LogRing::new(5);
373 ring.push(1);
374 ring.push(2);
375 ring.push(3);
376
377 ring.reset();
378 assert!(ring.is_empty());
379 assert_eq!(ring.total_count(), 0);
380 assert_eq!(ring.first_index(), 0);
381 }
382
383 #[test]
384 fn front_and_back() {
385 let mut ring = LogRing::new(3);
386 assert_eq!(ring.front(), None);
387 assert_eq!(ring.back(), None);
388
389 ring.push("first");
390 ring.push("middle");
391 ring.push("last");
392
393 assert_eq!(ring.front(), Some(&"first"));
394 assert_eq!(ring.back(), Some(&"last"));
395
396 ring.push("newest"); assert_eq!(ring.front(), Some(&"middle"));
398 assert_eq!(ring.back(), Some(&"newest"));
399 }
400
401 #[test]
402 fn iter_yields_oldest_to_newest() {
403 let mut ring = LogRing::new(3);
404 ring.push(1);
405 ring.push(2);
406 ring.push(3);
407
408 let items: Vec<_> = ring.iter().copied().collect();
409 assert_eq!(items, vec![1, 2, 3]);
410 }
411
412 #[test]
413 fn iter_indexed_includes_absolute_indices() {
414 let mut ring = LogRing::new(2);
415 ring.push("a");
416 ring.push("b");
417 ring.push("c"); let indexed: Vec<_> = ring.iter_indexed().collect();
420 assert_eq!(indexed, vec![(1, &"b"), (2, &"c")]);
421 }
422
423 #[test]
424 fn extend_adds_multiple_items() {
425 let mut ring = LogRing::new(5);
426 ring.extend(vec![1, 2, 3]);
427
428 assert_eq!(ring.len(), 3);
429 assert_eq!(ring.total_count(), 3);
430 }
431
432 #[test]
433 fn from_iter_creates_ring() {
434 let ring: LogRing<i32> = vec![1, 2, 3, 4, 5].into_iter().collect();
435 assert_eq!(ring.len(), 5);
436 assert_eq!(ring.capacity(), 5);
437 }
438
439 #[test]
440 fn default_has_reasonable_capacity() {
441 let ring: LogRing<i32> = LogRing::default();
442 assert_eq!(ring.capacity(), 1024);
443 }
444
445 #[test]
446 fn get_mut_allows_modification() {
447 let mut ring = LogRing::new(3);
448 ring.push(1);
449 ring.push(2);
450
451 if let Some(item) = ring.get_mut(0) {
452 *item = 10;
453 }
454
455 assert_eq!(ring.get(0), Some(&10));
456 }
457
458 #[test]
459 fn drain_removes_all_items() {
460 let mut ring = LogRing::new(5);
461 ring.push(1);
462 ring.push(2);
463 ring.push(3);
464
465 let drained: Vec<_> = ring.drain().collect();
466 assert_eq!(drained, vec![1, 2, 3]);
467 assert!(ring.is_empty());
468 assert_eq!(ring.total_count(), 3); }
470
471 #[test]
472 fn handles_large_total_count() {
473 let mut ring = LogRing::new(2);
474 for i in 0..1000 {
475 ring.push(i);
476 }
477
478 assert_eq!(ring.len(), 2);
479 assert_eq!(ring.total_count(), 1000);
480 assert_eq!(ring.first_index(), 998);
481 assert_eq!(ring.get(998), Some(&998));
482 assert_eq!(ring.get(999), Some(&999));
483 }
484}