use core::fmt;
use core::ops::{Index, IndexMut};
#[derive(Debug)]
pub struct ArrayVec<T, const N: usize> {
inner: heapless::Vec<T, N>,
}
#[derive(Debug, Clone)]
pub enum ArrayVecError {
CapacityOverflow,
}
impl fmt::Display for ArrayVecError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CapacityOverflow => f.write_str("capacity overflow"),
}
}
}
impl core::error::Error for ArrayVecError {}
impl<T, const N: usize> ArrayVec<T, N> {
pub const fn new() -> Self {
Self {
inner: heapless::Vec::new(),
}
}
pub fn try_push(&mut self, value: T) -> Result<(), ArrayVecError> {
self.inner
.push(value)
.map_err(|_| ArrayVecError::CapacityOverflow)
}
pub fn push(&mut self, value: T) {
self.try_push(value).expect("ArrayVec: ran out of capacity");
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn as_slice(&self) -> &[T] {
self.inner.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.inner.as_mut_slice()
}
pub fn iter(&self) -> core::slice::Iter<'_, T> {
self.inner.iter()
}
pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> {
self.inner.iter_mut()
}
pub fn reverse(&mut self) {
self.inner.reverse();
}
pub fn as_ptr(&self) -> *const T {
self.inner.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut T {
self.inner.as_mut_ptr()
}
}
impl<T, const N: usize> Default for ArrayVec<T, N> {
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> ArrayVec<T, N>
where
T: Copy + PartialEq,
{
pub fn contains(&self, value: &T) -> bool {
self.inner.contains(value)
}
}
impl<T, const N: usize> ArrayVec<T, N>
where
T: Copy + Ord,
{
pub fn sort_unstable(&mut self) {
self.inner.sort_unstable();
}
}
impl<T, const N: usize> Index<usize> for ArrayVec<T, N>
where
T: Copy,
{
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.inner[index]
}
}
impl<T, const N: usize> IndexMut<usize> for ArrayVec<T, N>
where
T: Copy,
{
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.inner[index]
}
}
#[derive(Clone, Copy)]
pub struct RingBuf<T: Copy, const N: usize> {
buf: [Option<T>; N],
head: usize,
tail: usize,
}
impl<T: Copy, const N: usize> RingBuf<T, N> {
pub const SIZE: usize = N;
pub const fn new() -> Self {
Self {
buf: [None; N],
head: 0,
tail: 0,
}
}
pub const fn is_empty(&self) -> bool {
self.head == self.tail
}
pub const fn len(&self) -> usize {
(self.head + Self::SIZE - self.tail) % Self::SIZE
}
pub const fn is_full(&self) -> bool {
(self.head + 1) % N == self.tail
}
pub const fn max_capacity(&self) -> usize {
Self::SIZE - 1
}
pub fn try_push(&mut self, value: T) -> Result<(), T> {
if self.is_full() {
return Err(value);
}
unsafe { self.push_unchecked(value) };
Ok(())
}
pub fn push(&mut self, value: T) {
if self.try_push(value).is_err() {
panic!("ringbuf is full");
}
}
pub unsafe fn push_unchecked(&mut self, value: T) {
self.buf[self.head] = Some(value);
self.head = (self.head + 1) % N;
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let value = self.buf[self.tail].take();
self.tail = (self.tail + 1) % N;
value
}
}
impl<T: Copy, const N: usize> Default for RingBuf<T, N> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::sync::atomic::{AtomicUsize, Ordering};
static_assertions::assert_impl_all!(RingBuf<u8, 4>: Clone, Copy);
#[test]
fn array_vec_preserves_values_and_capacity_errors() {
let mut values = ArrayVec::<u8, 2>::new();
values.push(2);
values.push(1);
assert!(matches!(
values.try_push(3),
Err(ArrayVecError::CapacityOverflow)
));
values.sort_unstable();
assert_eq!(values.as_slice(), &[1, 2]);
}
#[test]
fn array_vec_drops_stored_values() {
static DROPS: AtomicUsize = AtomicUsize::new(0);
struct DropCounter;
impl Drop for DropCounter {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::Relaxed);
}
}
DROPS.store(0, Ordering::Relaxed);
{
let mut values = ArrayVec::<DropCounter, 2>::new();
values.push(DropCounter);
values.push(DropCounter);
}
assert_eq!(DROPS.load(Ordering::Relaxed), 2);
}
#[test]
#[should_panic]
fn array_vec_rejects_uninitialized_index() {
let mut values = ArrayVec::<u8, 2>::new();
values.push(1);
let _ = values[1];
}
#[test]
fn ring_buffer_wraps_and_preserves_fifo_order() {
let mut values = RingBuf::<u8, 4>::new();
values.push(1);
values.push(2);
values.push(3);
assert!(values.is_full());
assert_eq!(values.try_push(4), Err(4));
assert_eq!(values.pop(), Some(1));
values.push(4);
assert_eq!(values.pop(), Some(2));
assert_eq!(values.pop(), Some(3));
assert_eq!(values.pop(), Some(4));
assert_eq!(values.pop(), None);
}
}