Skip to main content

bytearray_ringbuffer/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3pub struct BytearrayRingbuffer<const N: usize> {
4    buffer: [u8; N],
5    /// points to where the next packet will be written
6    head: usize,
7    /// points to where the oldest packet starts
8    tail: usize,
9    /// resolves ambiguity between head == tail for empty and full
10    empty: bool,
11}
12
13#[derive(Copy, Clone, Debug)]
14pub struct NotEnoughSpaceError;
15
16impl<const N: usize> BytearrayRingbuffer<N> {
17    pub const fn new() -> Self {
18        assert!(N > 8);
19        assert!(N < (u32::MAX as usize));
20        Self {
21            buffer: [0; N],
22            head: 0,
23            tail: 0,
24            empty: true,
25        }
26    }
27
28    /// number of bytes available for payload, 8 bytes for header + end are already subtracted
29    pub const fn free(&self) -> usize {
30        self.bytes_unused().saturating_sub(8)
31    }
32
33    /// add entry, returns false if there was not enough space
34    pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
35        self._push(data, false)
36    }
37
38    /// add entry, discard old entries if there was not enough space
39    pub fn push_force(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
40        self._push(data, true)
41    }
42
43    /// number of bytes are currently not in use
44    const fn bytes_unused(&self) -> usize {
45        if self.empty {
46            N
47        } else if self.head > self.tail {
48            N + self.tail - self.head
49        } else {
50            self.tail - self.head
51        }
52    }
53
54    fn _push(&mut self, data: &[u8], force: bool) -> Result<(), NotEnoughSpaceError> {
55        assert!(data.len() <= u32::MAX as usize);
56
57        // data is longer than entire buffer
58        if data.len() > N - 8 {
59            return Err(NotEnoughSpaceError);
60        }
61
62        // need to overwrite old data to fit new data
63        if (data.len() + 8) > self.bytes_unused() {
64            if !force {
65                return Err(NotEnoughSpaceError);
66            }
67            while (data.len() + 8) > self.bytes_unused() {
68                self.pop_front();
69            }
70        }
71
72        // write length + data + length
73        let addr_a = self.head;
74        let addr_b = add_wrapping::<N>(self.head, 4);
75        let addr_c = add_wrapping::<N>(self.head, 4 + data.len());
76        let len_buffer: [u8; 4] = (data.len() as u32).to_ne_bytes();
77        write_wrapping(&mut self.buffer, addr_a, &len_buffer);
78        write_wrapping(&mut self.buffer, addr_b, data);
79        write_wrapping(&mut self.buffer, addr_c, &len_buffer);
80
81        self.head = add_wrapping::<N>(self.head, 8 + data.len());
82        self.empty = false;
83
84        Ok(())
85    }
86
87    pub fn pop_front(&mut self) -> Option<(&[u8], &[u8])> {
88        if self.empty {
89            return None;
90        }
91        let mut len_buffer = [0; 4];
92        read_wrapping(&self.buffer, self.tail, &mut len_buffer);
93        let len = u32::from_ne_bytes(len_buffer) as usize;
94
95        let index_data = add_wrapping::<N>(self.tail, 4);
96        let len_a = (N - index_data).min(len);
97        let a = &self.buffer[index_data..index_data + len_a];
98        let b = if len_a == len {
99            &[]
100        } else {
101            &self.buffer[..len - len_a]
102        };
103
104        self.tail = add_wrapping::<N>(self.tail, len + 8);
105        self.empty = self.head == self.tail;
106        Some((a, b))
107    }
108
109    pub fn iter_backwards<'a>(&'a self) -> IterBackwards<'a, N> {
110        IterBackwards {
111            buffer: &self.buffer,
112            head: self.head,
113            tail: self.tail,
114            empty: self.empty,
115        }
116    }
117
118    pub fn iter<'a>(&'a self) -> Iter<'a, N> {
119        Iter {
120            buffer: &self.buffer,
121            head: self.head,
122            tail: self.tail,
123            empty: self.empty,
124        }
125    }
126
127    /// return the number of valid entries
128    pub fn count(&self) -> usize {
129        self.iter_backwards().count()
130    }
131
132    pub fn nth(&self, n: usize) -> Option<(&[u8], &[u8])> {
133        self.iter_backwards().nth(n)
134    }
135}
136
137pub struct IterBackwards<'a, const N: usize> {
138    buffer: &'a [u8; N],
139    head: usize,
140    tail: usize,
141    empty: bool,
142}
143
144impl<'a, const N: usize> Iterator for IterBackwards<'a, N> {
145    type Item = (&'a [u8], &'a [u8]);
146
147    fn next(&mut self) -> Option<Self::Item> {
148        if self.empty {
149            return None;
150        }
151
152        // read length of newest packet
153        let index_len = sub_wrapping::<N>(self.head, 4);
154        let mut buf = [0u8; 4];
155        read_wrapping(self.buffer, index_len, &mut buf);
156        let len_data = u32::from_ne_bytes(buf) as usize;
157        debug_assert!((len_data + 8) <= N);
158
159        #[cfg(test)]
160        {
161            let index_len = sub_wrapping::<N>(self.head, 8 + len_data);
162            let mut buf = [0u8; 4];
163            read_wrapping(self.buffer, index_len, &mut buf);
164            let len_2 = u32::from_ne_bytes(buf) as usize;
165            assert_eq!(len_data, len_2);
166        }
167
168        // read out data
169        let index_data = sub_wrapping::<N>(self.head, 4 + len_data);
170        let first = (N - index_data).min(len_data);
171        let slice_a = &self.buffer[index_data..index_data + first];
172        let slice_b = if first < len_data {
173            &self.buffer[..len_data - first]
174        } else {
175            &[]
176        };
177
178        self.head = sub_wrapping::<N>(self.head, 8 + len_data);
179        self.empty = self.head == self.tail;
180
181        Some((slice_a, slice_b))
182    }
183}
184
185impl<const N: usize> Default for BytearrayRingbuffer<N> {
186    fn default() -> Self {
187        Self::new()
188    }
189}
190
191pub struct Iter<'a, const N: usize> {
192    buffer: &'a [u8; N],
193    head: usize,
194    tail: usize,
195    empty: bool,
196}
197
198impl<'a, const N: usize> Iterator for Iter<'a, N> {
199    type Item = (&'a [u8], &'a [u8]);
200
201    fn next(&mut self) -> Option<Self::Item> {
202        if self.empty {
203            return None;
204        }
205
206        // check how many bytes are valid
207        let bytes_used = if self.head > self.tail {
208            N + self.tail - self.head
209        } else {
210            self.tail - self.head
211        };
212        let bytes_valid = N - bytes_used;
213        debug_assert!(bytes_valid >= 8);
214
215        // read length of newest packet
216        let mut buf = [0u8; 4];
217        read_wrapping(self.buffer, self.tail, &mut buf);
218        let len_data = u32::from_ne_bytes(buf) as usize;
219        debug_assert!((len_data + 8) <= N);
220        debug_assert!((len_data + 8) <= bytes_valid);
221
222        // read out data
223        let index_data = add_wrapping::<N>(self.tail, 4);
224        let first = (N - index_data).min(len_data);
225        let slice_a = &self.buffer[index_data..index_data + first];
226        let slice_b = if first < len_data {
227            &self.buffer[..len_data - first]
228        } else {
229            &[]
230        };
231
232        self.tail = add_wrapping::<N>(self.tail, 8 + len_data);
233        self.empty = self.head == self.tail;
234
235        Some((slice_a, slice_b))
236    }
237}
238
239fn add_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
240    debug_assert!(addr < N);
241    debug_assert!(offset <= N);
242    let s = addr + offset;
243    if s < N { s } else { s - N }
244}
245
246fn sub_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
247    debug_assert!(addr < N);
248    debug_assert!(offset <= N);
249    if addr >= offset {
250        addr - offset
251    } else {
252        N + addr - offset
253    }
254}
255
256/// write data to buffer, starting at index and wrapping around at the end of the buffer
257fn write_wrapping(buffer: &mut [u8], index: usize, data: &[u8]) {
258    let first = (buffer.len() - index).min(data.len());
259    buffer[index..index + first].copy_from_slice(&data[..first]);
260    if first < data.len() {
261        buffer[..data.len() - first].copy_from_slice(&data[first..]);
262    }
263}
264
265fn read_wrapping(buffer: &[u8], index: usize, data: &mut [u8]) {
266    let first = (buffer.len() - index).min(data.len());
267    data[..first].copy_from_slice(&buffer[index..index + first]);
268    if first < data.len() {
269        let remaining = data.len() - first;
270        data[first..].copy_from_slice(&buffer[..remaining]);
271    }
272}
273
274#[cfg(test)]
275mod tests {
276    use std::collections::VecDeque;
277
278    use super::BytearrayRingbuffer;
279
280    #[test]
281    fn push_some_packets() {
282        const N: usize = 64;
283        for start_offset in 0..N {
284            let mut buf = BytearrayRingbuffer::<N>::new();
285            buf.head = start_offset;
286            buf.tail = start_offset;
287
288            let free = 64 - 8;
289            assert_eq!(buf.free(), free);
290
291            buf.push(b"01234567").unwrap();
292            let free = free - 8 - 8;
293            assert_eq!(buf.free(), free);
294
295            buf.push(b"").unwrap();
296            let free = free - 8;
297            assert_eq!(buf.free(), free);
298
299            buf.push(b"0123").unwrap();
300            let free = free - 4 - 8;
301            assert_eq!(buf.free(), free);
302
303            buf.push(b"0123").unwrap();
304            let free = free - 4 - 8;
305            assert_eq!(buf.free(), free);
306        }
307    }
308
309    #[test]
310    fn push_force() {
311        let mut buf = BytearrayRingbuffer::<16>::new();
312        assert_eq!(buf.bytes_unused(), 16);
313
314        let a = b"012345";
315        let b = b"0123";
316
317        buf.push(a).unwrap();
318        assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
319
320        buf.push(b).unwrap_err();
321        assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
322
323        buf.push_force(b).unwrap();
324        assert_eq!(buf.bytes_unused(), 16 - b.len() - 8);
325    }
326
327    #[test]
328    fn push_all_data_lengths() {
329        for n in 0..(32 - 8) {
330            let mut buf = BytearrayRingbuffer::<32>::new();
331            // push n bytes
332            let data = (0..n as u8).collect::<Vec<u8>>();
333
334            assert_eq!(buf.free(), 32 - 8);
335            buf.push(&data).unwrap();
336            assert_eq!(buf.free(), (32usize - 16).saturating_sub(n));
337        }
338    }
339
340    #[test]
341    fn push_sum_of_lengths_possible() {
342        let mut buf = BytearrayRingbuffer::<32>::new();
343        // push 2 x 8 bytes
344        assert_eq!(buf.free(), 32 - 8);
345        buf.push(b"01234567").unwrap();
346        assert_eq!(buf.free(), 32 - 8 - 16);
347        buf.push(b"01234567").unwrap();
348        assert_eq!(buf.free(), 0);
349    }
350
351    #[test]
352    fn push_pop() {
353        const N: usize = 64;
354        for start_offset in 0..N {
355            eprintln!("--------------");
356            let mut buf = BytearrayRingbuffer::<N>::new();
357            buf.head = start_offset;
358            buf.tail = start_offset;
359
360            let data = b"01234567";
361            buf.push(data).unwrap();
362
363            let (a, b) = buf.pop_front().unwrap();
364            let mut out = Vec::new();
365            out.extend_from_slice(a);
366            out.extend_from_slice(b);
367
368            dbg!(out.as_slice());
369            assert!(data == out.as_slice());
370
371            assert_eq!(buf.head, buf.tail);
372            assert_eq!(buf.bytes_unused(), N);
373        }
374    }
375
376    #[test]
377    fn push_read_back() {
378        let data = [b"hello world" as &[u8], b"", b"test"];
379
380        const N: usize = 64;
381        for start_offset in 0..N {
382            let mut buf = BytearrayRingbuffer::<N>::new();
383            buf.head = start_offset;
384            buf.tail = start_offset;
385
386            for &d in &data {
387                buf.push(d).unwrap();
388            }
389
390            // test forward iteration
391            let mut it = buf.iter();
392            for &d in data.iter() {
393                let (a, b) = it.next().unwrap();
394                let mut ab = Vec::new();
395                ab.extend_from_slice(a);
396                ab.extend_from_slice(b);
397                let ab = ab.as_slice();
398                assert_eq!(d, ab);
399            }
400            assert_eq!(it.next(), None);
401
402            // test backward iteration
403            let mut it = buf.iter_backwards();
404            for &d in data.iter().rev() {
405                let (a, b) = it.next().unwrap();
406                let mut ab = Vec::new();
407                ab.extend_from_slice(a);
408                ab.extend_from_slice(b);
409                let ab = ab.as_slice();
410                assert_eq!(d, ab);
411            }
412            assert_eq!(it.next(), None);
413        }
414    }
415
416    #[test]
417    fn push_count() {
418        let mut buf = BytearrayRingbuffer::<64>::new();
419        buf.push(b"1234").unwrap();
420        assert_eq!(buf.count(), 1);
421        buf.push(b"1234").unwrap();
422        assert_eq!(buf.count(), 2);
423        buf.push(b"1234").unwrap();
424        assert_eq!(buf.count(), 3);
425    }
426
427    fn test_with_readback<const N: usize>(words: &[&'static str]) {
428        eprintln!("--------------------------");
429        let mut buf = BytearrayRingbuffer::<N>::new();
430        let mut current_words = VecDeque::new();
431        for &word in words {
432            eprintln!("adding {word:?}");
433            let word = word.to_owned();
434            let current_bytes: usize = current_words.iter().map(|w: &String| w.len() + 8).sum();
435            if current_bytes + 8 + word.len() > N {
436                current_words.pop_front();
437            }
438
439            buf.push_force(word.as_bytes()).unwrap();
440            current_words.push_back(word);
441
442            for (a, b) in buf.iter_backwards().zip(current_words.iter().rev()) {
443                eprintln!("read back {b:?}");
444                let mut st = String::new();
445                st.push_str(core::str::from_utf8(a.0).unwrap());
446                st.push_str(core::str::from_utf8(a.1).unwrap());
447                assert_eq!(st, *b);
448            }
449        }
450    }
451
452    #[test]
453    fn readback_various() {
454        test_with_readback::<32>(&["ab", "123", "hello", "world"]);
455        test_with_readback::<32>(&["", "", "a", "", "", ""]);
456        test_with_readback::<32>(&["", "", "ab", "", "", ""]);
457        test_with_readback::<32>(&["", "", "abc", "", "", ""]);
458        test_with_readback::<32>(&["", "", "abcd", "", "", ""]);
459        test_with_readback::<32>(&["", "", "abcde", "", "", ""]);
460
461        test_with_readback::<24>(&["0", "1", "a", "2", "3", "4"]);
462        test_with_readback::<24>(&["0", "1", "ab", "2", "3", "4"]);
463        test_with_readback::<24>(&["0", "1", "abc", "2", "3", "4"]);
464        test_with_readback::<24>(&["0", "1", "abcd", "2", "3", "4"]);
465        test_with_readback::<24>(&["0", "1", "abcde", "2", "3", "4"]);
466        test_with_readback::<24>(&["0", "1", "abcdef", "2", "3", "4"]);
467        test_with_readback::<24>(&["0", "1", "abcdefg", "2", "3", "4"]);
468    }
469}