Skip to main content

prettyping_rs/
ring_buffer.rs

1#[derive(Debug, Clone, PartialEq, Eq)]
2pub struct RingBuffer<T> {
3    data: Vec<Option<T>>,
4    head: usize,
5    len: usize,
6}
7
8impl<T> RingBuffer<T> {
9    #[must_use]
10    pub fn with_capacity(capacity: usize) -> Self {
11        Self {
12            data: std::iter::repeat_with(|| None).take(capacity).collect(),
13            head: 0,
14            len: 0,
15        }
16    }
17
18    #[must_use]
19    pub fn capacity(&self) -> usize {
20        self.data.len()
21    }
22
23    #[must_use]
24    pub fn len(&self) -> usize {
25        self.len
26    }
27
28    #[must_use]
29    pub fn is_empty(&self) -> bool {
30        self.len == 0
31    }
32
33    pub fn push(&mut self, value: T) -> Option<T> {
34        let capacity = self.capacity();
35        if capacity == 0 {
36            return Some(value);
37        }
38
39        if self.len < capacity {
40            let index = (self.head + self.len) % capacity;
41            self.data[index] = Some(value);
42            self.len += 1;
43            return None;
44        }
45
46        let index = self.head;
47        self.head = (self.head + 1) % capacity;
48        self.data[index].replace(value)
49    }
50
51    #[must_use]
52    pub fn iter(&self) -> RingBufferIter<'_, T> {
53        RingBufferIter {
54            buffer: self,
55            offset: 0,
56        }
57    }
58}
59
60pub struct RingBufferIter<'a, T> {
61    buffer: &'a RingBuffer<T>,
62    offset: usize,
63}
64
65impl<'a, T> Iterator for RingBufferIter<'a, T> {
66    type Item = &'a T;
67
68    fn next(&mut self) -> Option<Self::Item> {
69        if self.offset >= self.buffer.len {
70            return None;
71        }
72
73        let index = (self.buffer.head + self.offset) % self.buffer.capacity();
74        self.offset += 1;
75        self.buffer.data[index].as_ref()
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::RingBuffer;
82
83    #[test]
84    fn overwrites_oldest_value_when_full() {
85        let mut ring = RingBuffer::with_capacity(3);
86
87        assert_eq!(ring.push(1), None);
88        assert_eq!(ring.push(2), None);
89        assert_eq!(ring.push(3), None);
90        assert_eq!(ring.push(4), Some(1));
91
92        let values: Vec<i32> = ring.iter().copied().collect();
93        assert_eq!(values, vec![2, 3, 4]);
94    }
95
96    #[test]
97    fn empty_capacity_discards_values() {
98        let mut ring = RingBuffer::with_capacity(0);
99
100        assert_eq!(ring.push(42), Some(42));
101        assert!(ring.is_empty());
102        assert_eq!(ring.len(), 0);
103        assert_eq!(ring.capacity(), 0);
104    }
105}