uucore/features/
ringbuffer.rs

1// This file is part of the uutils coreutils package.
2//
3// For the full copyright and license information, please view the LICENSE
4// file that was distributed with this source code.
5//! A fixed-size ring buffer.
6use std::collections::VecDeque;
7
8/// A fixed-size ring buffer backed by a `VecDeque`.
9///
10/// If the ring buffer is not full, then calling the [`push_back`]
11/// method appends elements, as in a [`VecDeque`]. If the ring buffer
12/// is full, then calling [`push_back`] removes the element at the
13/// front of the buffer (in a first-in, first-out manner) before
14/// appending the new element to the back of the buffer.
15///
16/// Use [`from_iter`] to take the last `size` elements from an
17/// iterator.
18///
19/// # Examples
20///
21/// After exceeding the size limit, the oldest elements are dropped in
22/// favor of the newest element:
23///
24/// ```rust,ignore
25/// let mut buffer: RingBuffer<u8> = RingBuffer::new(2);
26/// buffer.push_back(0);
27/// buffer.push_back(1);
28/// buffer.push_back(2);
29/// assert_eq!(vec![1, 2], buffer.data);
30/// ```
31///
32/// Take the last `n` elements from an iterator:
33///
34/// ```rust,ignore
35/// let iter = [0, 1, 2].iter();
36/// let actual = RingBuffer::from_iter(iter, 2).data;
37/// let expected = VecDeque::from_iter([1, 2].iter());
38/// assert_eq!(expected, actual);
39/// ```
40///
41/// [`push_back`]: struct.RingBuffer.html#method.push_back
42/// [`from_iter`]: struct.RingBuffer.html#method.from_iter
43pub struct RingBuffer<T> {
44    /// The data stored in the ring buffer.
45    pub data: VecDeque<T>,
46
47    /// The maximum number of elements that the ring buffer can hold.
48    size: usize,
49}
50
51impl<T> RingBuffer<T> {
52    /// Create a new ring buffer with a maximum size of `size`.
53    pub fn new(size: usize) -> Self {
54        Self {
55            data: VecDeque::new(),
56            size,
57        }
58    }
59
60    /// Create a new ring buffer from an iterator.
61    pub fn from_iter(iter: impl Iterator<Item = T>, size: usize) -> Self {
62        let mut ring_buffer = Self::new(size);
63        for value in iter {
64            ring_buffer.push_back(value);
65        }
66        ring_buffer
67    }
68
69    /// Append a value to the end of the ring buffer.
70    ///
71    /// If the ring buffer is not full, this method return [`None`]. If
72    /// the ring buffer is full, appending a new element will cause the
73    /// oldest element to be evicted. In that case this method returns
74    /// that element, or `None`.
75    ///
76    /// In the special case where the size limit is zero, each call to
77    /// this method with input `value` returns `Some(value)`, because
78    /// the input is immediately evicted.
79    ///
80    /// # Examples
81    ///
82    /// Appending an element when the buffer is full returns the oldest
83    /// element:
84    ///
85    /// ```rust,ignore
86    /// let mut buf = RingBuffer::new(3);
87    /// assert_eq!(None, buf.push_back(0));
88    /// assert_eq!(None, buf.push_back(1));
89    /// assert_eq!(None, buf.push_back(2));
90    /// assert_eq!(Some(0), buf.push_back(3));
91    /// ```
92    ///
93    /// If the size limit is zero, then this method always returns the
94    /// input value:
95    ///
96    /// ```rust,ignore
97    /// let mut buf = RingBuffer::new(0);
98    /// assert_eq!(Some(0), buf.push_back(0));
99    /// assert_eq!(Some(1), buf.push_back(1));
100    /// assert_eq!(Some(2), buf.push_back(2));
101    /// ```
102    pub fn push_back(&mut self, value: T) -> Option<T> {
103        if self.size == 0 {
104            return Some(value);
105        }
106        let result = if self.size <= self.data.len() {
107            self.data.pop_front()
108        } else {
109            None
110        };
111        self.data.push_back(value);
112        result
113    }
114}
115
116#[cfg(test)]
117mod tests {
118
119    use crate::ringbuffer::RingBuffer;
120    use std::collections::VecDeque;
121
122    #[test]
123    fn test_size_limit_zero() {
124        let mut buf = RingBuffer::new(0);
125        assert_eq!(Some(0), buf.push_back(0));
126        assert_eq!(Some(1), buf.push_back(1));
127        assert_eq!(Some(2), buf.push_back(2));
128    }
129
130    #[test]
131    fn test_evict_oldest() {
132        let mut buf = RingBuffer::new(2);
133        assert_eq!(None, buf.push_back(0));
134        assert_eq!(None, buf.push_back(1));
135        assert_eq!(Some(0), buf.push_back(2));
136    }
137
138    #[test]
139    fn test_from_iter() {
140        let iter = [0, 1, 2].iter();
141        let actual = RingBuffer::from_iter(iter, 2).data;
142        let expected: VecDeque<&i32> = [1, 2].iter().collect();
143        assert_eq!(expected, actual);
144    }
145}