Skip to main content

rs_matter/utils/storage/
ringbuf.rs

1/*
2 *
3 *    Copyright (c) 2024-2025 Project CHIP Authors
4 *
5 *    Licensed under the Apache License, Version 2.0 (the "License");
6 *    you may not use this file except in compliance with the License.
7 *    You may obtain a copy of the License at
8 *
9 *        http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *    Unless required by applicable law or agreed to in writing, software
12 *    distributed under the License is distributed on an "AS IS" BASIS,
13 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *    See the License for the specific language governing permissions and
15 *    limitations under the License.
16 */
17
18use core::cmp::min;
19
20use crate::utils::init::{init, Init};
21
22/// A ring buffer of a fixed capacity `N` using owned storage.
23#[derive(Debug)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub struct RingBuf<const N: usize> {
26    buf: crate::utils::storage::Vec<u8, N>,
27    start: usize,
28    end: usize,
29    non_empty: bool,
30}
31
32impl<const N: usize> Default for RingBuf<N> {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl<const N: usize> RingBuf<N> {
39    /// Create a new ring buffer.
40    #[inline(always)]
41    pub const fn new() -> Self {
42        Self {
43            buf: crate::utils::storage::Vec::new(),
44            start: 0,
45            end: 0,
46            non_empty: false,
47        }
48    }
49
50    /// Create an in-place initializer for the ring buffer.
51    pub fn init() -> impl Init<Self> {
52        init!(Self {
53            buf <- crate::utils::storage::Vec::init(),
54            start: 0,
55            end: 0,
56            non_empty: false,
57        })
58    }
59
60    /// Push new data to the end of the buffer.
61    /// If the data does not fit in the buffer, the oldest data is dropped to make room for the new one.
62    ///
63    /// Return the new length of data in the buffer.
64    #[inline(always)]
65    pub fn push(&mut self, data: &[u8]) -> usize {
66        // Unwrap is safe because the max size of the buffer is N
67        unwrap!(self.buf.resize_default(N));
68
69        let mut offset = 0;
70
71        while offset < data.len() {
72            let len = min(self.buf.len() - self.end, data.len() - offset);
73
74            self.buf[self.end..self.end + len].copy_from_slice(&data[offset..offset + len]);
75
76            offset += len;
77
78            if self.non_empty && self.start >= self.end && self.start < self.end + len {
79                // Dropping oldest data
80                self.start = self.end + len;
81            }
82
83            self.end += len;
84
85            self.wrap();
86
87            self.non_empty = true;
88        }
89
90        self.len()
91    }
92
93    /// Push a single byte to the end of the buffer.
94    /// If the buffer is full, the oldest byte is dropped to make room for the new one.
95    ///
96    /// Return the new length of data in the buffer.
97    #[inline(always)]
98    pub fn push_byte(&mut self, data: u8) -> usize {
99        // Unwrap is safe because the max size of the buffer is N
100        unwrap!(self.buf.resize_default(N));
101
102        self.buf[self.end] = data;
103
104        if self.non_empty && self.start == self.end {
105            // Dropping oldest data
106            self.start = self.end + 1;
107        }
108
109        self.end += 1;
110
111        self.wrap();
112
113        self.non_empty = true;
114
115        self.len()
116    }
117
118    /// Pop one byte from the start of the buffer.
119    /// If the bufer is empty, return `None`.
120    #[inline(always)]
121    pub fn pop_byte(&mut self) -> Option<u8> {
122        let mut buf = [0; 1];
123
124        if self.pop(&mut buf) == 1 {
125            Some(buf[0])
126        } else {
127            None
128        }
129    }
130
131    /// Pop data from the start of the buffer.
132    /// Return the number of bytes copied to the output buffer.
133    #[inline(always)]
134    pub fn pop(&mut self, out_buf: &mut [u8]) -> usize {
135        let mut offset = 0;
136
137        while offset < out_buf.len() && self.non_empty {
138            let len = min(
139                if self.start < self.end {
140                    self.end
141                } else {
142                    self.buf.len()
143                } - self.start,
144                out_buf.len() - offset,
145            );
146
147            out_buf[offset..offset + len].copy_from_slice(&self.buf[self.start..self.start + len]);
148
149            self.start += len;
150
151            self.wrap();
152
153            if self.start == self.end {
154                self.non_empty = false
155            }
156
157            offset += len;
158        }
159
160        offset
161    }
162
163    /// Return `true` when the buffer is full.
164    #[inline(always)]
165    pub fn is_full(&self) -> bool {
166        self.start == self.end && self.non_empty
167    }
168
169    /// Return `true` when the buffer is empty.
170    #[inline(always)]
171    pub fn is_empty(&self) -> bool {
172        !self.non_empty
173    }
174
175    /// Return the current size of the data in the buffer.
176    #[inline(always)]
177    #[allow(unused)]
178    pub fn len(&self) -> usize {
179        if !self.non_empty {
180            0
181        } else if self.start < self.end {
182            self.end - self.start
183        } else {
184            self.buf.len() + self.end - self.start
185        }
186    }
187
188    /// Return the free space in the buffer.
189    #[inline(always)]
190    #[allow(unused)]
191    pub fn free(&self) -> usize {
192        N - self.len()
193    }
194
195    /// Clear the buffer.
196    #[inline(always)]
197    pub fn clear(&mut self) {
198        self.start = 0;
199        self.end = 0;
200        self.non_empty = false;
201    }
202
203    #[inline(always)]
204    fn wrap(&mut self) {
205        if self.start == self.buf.len() {
206            self.start = 0;
207        }
208
209        if self.end == self.buf.len() {
210            self.end = 0;
211        }
212    }
213}
214
215impl<const N: usize> Iterator for RingBuf<N> {
216    type Item = u8;
217
218    fn next(&mut self) -> Option<Self::Item> {
219        self.pop_byte()
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226
227    #[test]
228    fn push_pop() {
229        let mut rb = RingBuf::<4>::new();
230        assert!(rb.is_empty());
231
232        rb.push(&[0, 1, 2]);
233        assert_eq!(3, rb.len());
234        assert!(!rb.is_empty());
235        assert!(!rb.is_full());
236
237        rb.push(&[3]);
238        assert_eq!(4, rb.len());
239        assert!(!rb.is_empty());
240        assert!(rb.is_full());
241
242        let mut buf = [0; 256];
243
244        let len = rb.pop(&mut buf);
245        assert_eq!(4, len);
246        assert_eq!(&buf[0..4], &[0, 1, 2, 3]);
247        assert!(rb.is_empty());
248
249        rb.push(&[0, 1, 2, 3, 4, 5]);
250        assert_eq!(4, rb.len());
251        assert!(!rb.is_empty());
252        assert!(rb.is_full());
253
254        let len = rb.pop(&mut buf[..3]);
255        assert_eq!(3, len);
256        assert_eq!(&buf[0..len], &[2, 3, 4]);
257        assert!(!rb.is_empty());
258        assert!(!rb.is_full());
259
260        let len = rb.pop(&mut buf);
261        assert_eq!(1, len);
262        assert_eq!(&buf[0..len], &[5]);
263        assert!(rb.is_empty());
264        assert!(!rb.is_full());
265
266        let len = rb.pop(&mut buf);
267        assert_eq!(0, len);
268        assert!(rb.is_empty());
269        assert!(!rb.is_full());
270    }
271}