Skip to content

Instantly share code, notes, and snippets.

@matthewjberger
Created October 1, 2024 16:45
Show Gist options
  • Save matthewjberger/b15a71f061dd43e144955c17f2c314da to your computer and use it in GitHub Desktop.
Save matthewjberger/b15a71f061dd43e144955c17f2c314da to your computer and use it in GitHub Desktop.
A no-std fixed capacity ringbuffer in rust
#![no_std]
pub struct CircularBuffer<T, const N: usize> {
buffer: [T; N],
read_idx: usize,
write_idx: usize,
is_full: bool,
}
impl<T: Copy + Default, const N: usize> CircularBuffer<T, N> {
pub fn new() -> Self {
Self {
buffer: [T::default(); N],
read_idx: 0,
write_idx: 0,
is_full: false,
}
}
pub fn push(&mut self, item: T) {
self.buffer[self.write_idx] = item;
if self.is_full {
self.read_idx = (self.read_idx + 1) % N;
}
self.write_idx = (self.write_idx + 1) % N;
self.is_full = self.write_idx == self.read_idx;
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
let item = self.buffer[self.read_idx];
self.read_idx = (self.read_idx + 1) % N;
self.is_full = false;
Some(item)
}
}
pub fn is_empty(&self) -> bool {
!self.is_full && self.read_idx == self.write_idx
}
pub fn is_full(&self) -> bool {
self.is_full
}
pub fn len(&self) -> usize {
if self.is_full {
N
} else if self.write_idx >= self.read_idx {
self.write_idx - self.read_idx
} else {
N - (self.read_idx - self.write_idx)
}
}
pub fn capacity(&self) -> usize {
N
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_buffer_is_empty() {
let buffer: CircularBuffer<i32, 5> = CircularBuffer::new();
assert!(buffer.is_empty());
assert_eq!(buffer.len(), 0);
assert_eq!(buffer.capacity(), 5);
}
#[test]
fn test_push_and_pop() {
let mut buffer: CircularBuffer<i32, 3> = CircularBuffer::new();
buffer.push(1);
buffer.push(2);
buffer.push(3);
assert!(buffer.is_full());
assert_eq!(buffer.len(), 3);
assert_eq!(buffer.pop(), Some(1));
assert_eq!(buffer.pop(), Some(2));
assert_eq!(buffer.pop(), Some(3));
assert_eq!(buffer.pop(), None);
assert!(buffer.is_empty());
}
#[test]
fn test_overwrite_when_full() {
let mut buffer: CircularBuffer<i32, 3> = CircularBuffer::new();
buffer.push(1);
buffer.push(2);
buffer.push(3);
buffer.push(4);
assert!(buffer.is_full());
assert_eq!(buffer.len(), 3);
assert_eq!(buffer.pop(), Some(2));
assert_eq!(buffer.pop(), Some(3));
assert_eq!(buffer.pop(), Some(4));
assert_eq!(buffer.pop(), None);
}
#[test]
fn test_wrap_around() {
let mut buffer: CircularBuffer<i32, 3> = CircularBuffer::new();
buffer.push(1);
buffer.push(2);
assert_eq!(buffer.pop(), Some(1));
buffer.push(3);
buffer.push(4);
assert_eq!(buffer.len(), 3);
assert_eq!(buffer.pop(), Some(2));
assert_eq!(buffer.pop(), Some(3));
assert_eq!(buffer.pop(), Some(4));
assert_eq!(buffer.pop(), None);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment