#![cfg_attr(not(feature = "std"), no_std)]
#![warn(clippy::dbg_macro)]
#![warn(clippy::missing_const_for_fn)]
#![warn(clippy::missing_safety_doc)]
#![warn(clippy::must_use_candidate)]
#![warn(clippy::print_stderr)]
#![warn(clippy::print_stdout)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![warn(clippy::unnecessary_safety_comment)]
#![warn(clippy::unnecessary_safety_doc)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(unreachable_pub)]
#![warn(unused_qualifications)]
#![doc(test(attr(deny(warnings))))]
#[cfg(feature = "alloc")]
extern crate alloc;
mod cmp;
mod debug;
mod drain;
mod embedded_io;
mod hash;
mod io;
mod iter;
mod tests;
pub mod fixed;
#[cfg(feature = "alloc")]
pub mod heap;
use core::mem;
use core::mem::MaybeUninit;
use core::ops::Index;
use core::ops::IndexMut;
use core::ops::Range;
use core::ops::RangeBounds;
use core::ptr;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::borrow::ToOwned;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::boxed::Box;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;
pub use crate::drain::Drain;
pub use crate::fixed::FixedCircularBuffer;
pub use crate::iter::Iter;
pub use crate::iter::IterMut;
#[cfg(feature = "alloc")]
pub use crate::heap::HeapCircularBuffer;
#[inline]
const fn add_mod(x: usize, y: usize, m: usize) -> usize {
debug_assert!(m > 0);
debug_assert!(x <= m);
debug_assert!(y <= m);
let (z, overflow) = x.overflowing_add(y);
(z + (overflow as usize) * (usize::MAX % m + 1)) % m
}
#[inline]
const fn sub_mod(x: usize, y: usize, m: usize) -> usize {
debug_assert!(m > 0);
debug_assert!(x <= m);
debug_assert!(y <= m);
add_mod(x, m - y, m)
}
#[repr(C)]
struct Inner<T: ?Sized> {
size: usize,
start: usize,
items: T,
}
#[repr(transparent)]
pub struct CircularBuffer<T> {
inner: Inner<[MaybeUninit<T>]>,
}
impl<T> CircularBuffer<T> {
#[inline]
pub const fn len(&self) -> usize {
self.inner.size
}
#[inline]
pub const fn capacity(&self) -> usize {
self.inner.items.len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.inner.size == 0
}
#[inline]
pub const fn is_full(&self) -> bool {
self.inner.size == self.capacity()
}
#[inline]
#[must_use]
pub fn iter(&self) -> Iter<'_, T> {
Iter::new(self)
}
#[inline]
#[must_use]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut::new(self)
}
#[inline]
#[must_use]
pub fn range<R>(&self, range: R) -> Iter<'_, T>
where
R: RangeBounds<usize>,
{
Iter::over_range(self, range)
}
#[inline]
#[must_use]
pub fn range_mut<R>(&mut self, range: R) -> IterMut<'_, T>
where
R: RangeBounds<usize>,
{
IterMut::over_range(self, range)
}
#[inline]
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
where
R: RangeBounds<usize>,
{
Drain::over_range(self, range)
}
pub fn make_contiguous(&mut self) -> &mut [T] {
if self.capacity() == 0 || self.inner.size == 0 {
return &mut [];
}
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
let start = self.inner.start;
let end = add_mod(self.inner.start, self.inner.size, self.capacity());
let slice = if start < end {
&mut self.inner.items[start..end]
} else {
self.inner.start = 0;
self.inner.items.rotate_left(start);
&mut self.inner.items[..self.inner.size]
};
unsafe { slice.assume_init_mut() }
}
#[inline]
pub fn as_slices(&self) -> (&[T], &[T]) {
if self.capacity() == 0 || self.inner.size == 0 {
return (&[], &[]);
}
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
let start = self.inner.start;
let end = add_mod(self.inner.start, self.inner.size, self.capacity());
let (front, back) = if start < end {
(&self.inner.items[start..end], &[][..])
} else {
let (back, front) = self.inner.items.split_at(start);
(front, &back[..end])
};
unsafe { (front.assume_init_ref(), back.assume_init_ref()) }
}
#[inline]
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
if self.capacity() == 0 || self.inner.size == 0 {
return (&mut [][..], &mut [][..]);
}
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
let start = self.inner.start;
let end = add_mod(self.inner.start, self.inner.size, self.capacity());
let (front, back) = if start < end {
(&mut self.inner.items[start..end], &mut [][..])
} else {
let (back, front) = self.inner.items.split_at_mut(start);
(front, &mut back[..end])
};
unsafe { (front.assume_init_mut(), back.assume_init_mut()) }
}
#[inline]
const fn front_maybe_uninit_mut(&mut self) -> &mut MaybeUninit<T> {
debug_assert!(self.inner.size > 0, "empty buffer");
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
&mut self.inner.items[self.inner.start]
}
#[inline]
const fn front_maybe_uninit(&self) -> &MaybeUninit<T> {
debug_assert!(self.inner.size > 0, "empty buffer");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
&self.inner.items[self.inner.start]
}
#[inline]
const fn back_maybe_uninit(&self) -> &MaybeUninit<T> {
debug_assert!(self.inner.size > 0, "empty buffer");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
let back = add_mod(self.inner.start, self.inner.size - 1, self.capacity());
&self.inner.items[back]
}
#[inline]
const fn back_maybe_uninit_mut(&mut self) -> &mut MaybeUninit<T> {
debug_assert!(self.inner.size > 0, "empty buffer");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
let back = add_mod(self.inner.start, self.inner.size - 1, self.capacity());
&mut self.inner.items[back]
}
#[inline]
const fn get_maybe_uninit(&self, index: usize) -> &MaybeUninit<T> {
debug_assert!(self.inner.size > 0, "empty buffer");
debug_assert!(index < self.capacity(), "index out-of-bounds");
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
let index = add_mod(self.inner.start, index, self.capacity());
&self.inner.items[index]
}
#[inline]
const fn get_maybe_uninit_mut(&mut self, index: usize) -> &mut MaybeUninit<T> {
debug_assert!(self.inner.size > 0, "empty buffer");
debug_assert!(index < self.capacity(), "index out-of-bounds");
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
let index = add_mod(self.inner.start, index, self.capacity());
&mut self.inner.items[index]
}
#[inline]
fn slices_uninit_mut(&mut self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
if self.capacity() == 0 {
return (&mut [][..], &mut [][..]);
}
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
let start = self.inner.start;
let end = add_mod(start, self.inner.size, self.capacity());
if end < start {
(&mut self.inner.items[end..start], &mut [][..])
} else {
let (left, right) = self.inner.items.split_at_mut(end);
let left = &mut left[..start];
(right, left)
}
}
#[inline]
const fn inc_start(&mut self) {
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
self.inner.start = add_mod(self.inner.start, 1, self.capacity());
}
#[inline]
const fn dec_start(&mut self) {
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
self.inner.start = sub_mod(self.inner.start, 1, self.capacity());
}
#[inline]
const fn inc_size(&mut self) {
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
debug_assert!(self.inner.size < self.capacity(), "size at capacity limit");
self.inner.size += 1;
}
#[inline]
const fn dec_size(&mut self) {
debug_assert!(self.inner.size > 0, "size is 0");
self.inner.size -= 1;
}
#[inline]
unsafe fn drop_range(&mut self, range: Range<usize>) {
if range.is_empty() {
return;
}
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
debug_assert!(
range.start < self.inner.size,
"start of range out-of-bounds"
);
debug_assert!(range.end <= self.inner.size, "end of range out-of-bounds");
debug_assert!(range.start < range.end, "start of range is past its end");
debug_assert!(
range.start == 0 || range.end == self.inner.size,
"range does not include boundary of the buffer"
);
struct Dropper<'a, T>(&'a mut [MaybeUninit<T>]);
impl<T> Drop for Dropper<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(self.0.assume_init_mut());
}
}
}
let drop_from = add_mod(self.inner.start, range.start, self.capacity());
let drop_to = add_mod(self.inner.start, range.end, self.capacity());
let (right, left) = if drop_from < drop_to {
(&mut self.inner.items[drop_from..drop_to], &mut [][..])
} else {
let (left, right) = self.inner.items.split_at_mut(drop_from);
let left = &mut left[..drop_to];
(right, left)
};
let _left = Dropper(left);
let _right = Dropper(right);
}
#[inline]
pub const fn back(&self) -> Option<&T> {
if self.capacity() == 0 || self.inner.size == 0 {
return None;
}
Some(unsafe { self.back_maybe_uninit().assume_init_ref() })
}
#[inline]
pub const fn back_mut(&mut self) -> Option<&mut T> {
if self.capacity() == 0 || self.inner.size == 0 {
return None;
}
Some(unsafe { self.back_maybe_uninit_mut().assume_init_mut() })
}
#[inline]
pub const fn front(&self) -> Option<&T> {
if self.capacity() == 0 || self.inner.size == 0 {
return None;
}
Some(unsafe { self.front_maybe_uninit().assume_init_ref() })
}
#[inline]
pub const fn front_mut(&mut self) -> Option<&mut T> {
if self.capacity() == 0 || self.inner.size == 0 {
return None;
}
Some(unsafe { self.front_maybe_uninit_mut().assume_init_mut() })
}
#[inline]
pub const fn get(&self, index: usize) -> Option<&T> {
if self.capacity() == 0 || index >= self.inner.size {
return None;
}
Some(unsafe { self.get_maybe_uninit(index).assume_init_ref() })
}
#[inline]
pub const fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if self.capacity() == 0 || index >= self.inner.size {
return None;
}
Some(unsafe { self.get_maybe_uninit_mut(index).assume_init_mut() })
}
#[inline]
pub const fn nth_front(&self, index: usize) -> Option<&T> {
self.get(index)
}
#[inline]
pub const fn nth_front_mut(&mut self, index: usize) -> Option<&mut T> {
self.get_mut(index)
}
#[inline]
pub const fn nth_back(&self, index: usize) -> Option<&T> {
let index = match self.inner.size.checked_sub(index) {
Some(index) => index,
None => return None,
};
let index = match index.checked_sub(1) {
Some(index) => index,
None => return None,
};
self.get(index)
}
#[inline]
pub const fn nth_back_mut(&mut self, index: usize) -> Option<&mut T> {
let index = match self.inner.size.checked_sub(index) {
Some(index) => index,
None => return None,
};
let index = match index.checked_sub(1) {
Some(index) => index,
None => return None,
};
self.get_mut(index)
}
pub const fn push_back(&mut self, item: T) -> Option<T> {
if self.capacity() == 0 {
return Some(item);
}
if self.inner.size >= self.capacity() {
let replaced_item = mem::replace(
unsafe { self.front_maybe_uninit_mut().assume_init_mut() },
item,
);
self.inc_start();
Some(replaced_item)
} else {
self.inc_size();
self.back_maybe_uninit_mut().write(item);
None
}
}
pub const fn try_push_back(&mut self, item: T) -> Result<(), T> {
if self.inner.size >= self.capacity() {
Err(item)
} else {
self.inc_size();
self.back_maybe_uninit_mut().write(item);
Ok(())
}
}
pub const fn push_front(&mut self, item: T) -> Option<T> {
if self.capacity() == 0 {
return Some(item);
}
if self.inner.size >= self.capacity() {
let replaced_item = mem::replace(
unsafe { self.back_maybe_uninit_mut().assume_init_mut() },
item,
);
self.dec_start();
Some(replaced_item)
} else {
self.inc_size();
self.dec_start();
self.front_maybe_uninit_mut().write(item);
None
}
}
pub const fn try_push_front(&mut self, item: T) -> Result<(), T> {
if self.inner.size >= self.capacity() {
Err(item)
} else {
self.inc_size();
self.dec_start();
self.front_maybe_uninit_mut().write(item);
Ok(())
}
}
pub const fn pop_back(&mut self) -> Option<T> {
if self.capacity() == 0 || self.inner.size == 0 {
return None;
}
let back = unsafe { self.back_maybe_uninit().assume_init_read() };
self.dec_size();
Some(back)
}
pub const fn pop_front(&mut self) -> Option<T> {
if self.capacity() == 0 || self.inner.size == 0 {
return None;
}
let front = unsafe { self.front_maybe_uninit().assume_init_read() };
self.dec_size();
self.inc_start();
Some(front)
}
pub const fn remove(&mut self, index: usize) -> Option<T> {
if self.capacity() == 0 || index >= self.inner.size {
return None;
}
let index = add_mod(self.inner.start, index, self.capacity());
let back_index = add_mod(self.inner.start, self.inner.size - 1, self.capacity());
let item = unsafe { self.inner.items[index].assume_init_read() };
unsafe {
let ptr = self.inner.items.as_mut_ptr();
if back_index >= index {
ptr::copy(ptr.add(index).add(1), ptr.add(index), back_index - index);
} else {
ptr::copy(
ptr.add(index).add(1),
ptr.add(index),
self.capacity() - index - 1,
);
ptr::copy(ptr, ptr.add(self.capacity() - 1), 1);
ptr::copy(ptr.add(1), ptr, back_index);
}
}
self.dec_size();
Some(item)
}
pub const fn swap(&mut self, i: usize, j: usize) {
assert!(i < self.inner.size, "i index out-of-bounds");
assert!(j < self.inner.size, "j index out-of-bounds");
if i != j {
let i = add_mod(self.inner.start, i, self.capacity());
let j = add_mod(self.inner.start, j, self.capacity());
unsafe {
ptr::swap_nonoverlapping(&mut self.inner.items[i], &mut self.inner.items[j], 1)
};
}
}
pub const fn swap_remove_back(&mut self, index: usize) -> Option<T> {
if index >= self.inner.size {
return None;
}
self.swap(index, self.inner.size - 1);
self.pop_back()
}
pub const fn swap_remove_front(&mut self, index: usize) -> Option<T> {
if index >= self.inner.size {
return None;
}
self.swap(index, 0);
self.pop_front()
}
pub fn fill(&mut self, value: T)
where
T: Clone,
{
self.clear();
self.fill_spare(value);
}
pub fn fill_with<F>(&mut self, f: F)
where
F: FnMut() -> T,
{
self.clear();
self.fill_spare_with(f);
}
pub fn fill_spare(&mut self, value: T)
where
T: Clone,
{
if self.inner.size == self.capacity() {
return;
}
while self.inner.size < self.capacity() - 1 {
self.push_back(value.clone());
}
self.push_back(value);
}
pub fn fill_spare_with<F>(&mut self, mut f: F)
where
F: FnMut() -> T,
{
if self.capacity() == 0 {
return;
}
while self.inner.size < self.capacity() {
self.push_back(f());
}
}
pub fn truncate_back(&mut self, len: usize) {
if self.capacity() == 0 || len >= self.inner.size {
return;
}
let drop_range = len..self.inner.size;
unsafe { self.drop_range(drop_range) };
self.inner.size = len;
}
pub fn truncate_front(&mut self, len: usize) {
if self.capacity() == 0 || len >= self.inner.size {
return;
}
let drop_len = self.inner.size - len;
let drop_range = 0..drop_len;
unsafe { self.drop_range(drop_range) };
self.inner.start = add_mod(self.inner.start, drop_len, self.capacity());
self.inner.size = len;
}
#[inline]
pub fn clear(&mut self) {
self.truncate_back(0)
}
}
impl<T> CircularBuffer<T>
where
T: Clone,
{
pub fn extend_from_slice(&mut self, other: &[T]) {
if self.capacity() == 0 {
return;
}
debug_assert!(self.inner.start < self.capacity(), "start out-of-bounds");
debug_assert!(self.inner.size <= self.capacity(), "size out-of-bounds");
if other.len() < self.capacity() {
let free_size = self.capacity() - self.inner.size;
let final_size = if other.len() < free_size {
self.inner.size + other.len()
} else {
let truncate_to = self.capacity() - other.len();
self.truncate_front(truncate_to);
self.capacity()
};
let (right, left) = self.slices_uninit_mut();
let write_len = core::cmp::min(right.len(), other.len());
right[..write_len].write_clone_of_slice(&other[..write_len]);
let other = &other[write_len..];
debug_assert!(left.len() >= other.len());
let write_len = other.len();
left[..write_len].write_clone_of_slice(other);
self.inner.size = final_size;
} else {
self.clear();
self.inner.start = 0;
let other = &other[other.len() - self.capacity()..];
debug_assert_eq!(self.inner.items.len(), other.len());
self.inner.items.write_clone_of_slice(other);
self.inner.size = self.capacity();
}
}
#[must_use]
#[cfg(feature = "alloc")]
pub fn to_vec(&self) -> Vec<T> {
let (front, back) = self.as_slices();
let mut vec = Vec::with_capacity(self.len());
vec.extend_from_slice(front);
vec.extend_from_slice(back);
debug_assert_eq!(vec.len(), self.len());
vec
}
}
impl<T> Index<usize> for CircularBuffer<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
self.get(index).expect("index out-of-bounds")
}
}
impl<T> IndexMut<usize> for CircularBuffer<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).expect("index out-of-bounds")
}
}
impl<T> Extend<T> for CircularBuffer<T> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
iter.into_iter().for_each(|item| {
self.push_back(item);
});
}
}
impl<'a, T> Extend<&'a T> for CircularBuffer<T>
where
T: Copy,
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = &'a T>,
{
iter.into_iter().for_each(|item| {
self.push_back(*item);
});
}
}
impl<'a, T> IntoIterator for &'a CircularBuffer<T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
impl<'a, T> IntoIterator for &'a mut CircularBuffer<T> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IterMut::new(self)
}
}
#[cfg(feature = "alloc")]
impl<T> ToOwned for CircularBuffer<T>
where
T: Clone,
{
type Owned = HeapCircularBuffer<T>;
fn to_owned(&self) -> Self::Owned {
let (front, back) = self.as_slices();
let mut buf = HeapCircularBuffer::<T>::with_capacity(self.capacity());
buf.extend_from_slice(front);
buf.extend_from_slice(back);
buf
}
}
impl<T> Drop for CircularBuffer<T> {
fn drop(&mut self) {
self.clear();
}
}
#[cfg(feature = "alloc")]
impl<T> Clone for Box<CircularBuffer<T>>
where
T: Clone,
{
fn clone(&self) -> Box<CircularBuffer<T>> {
let (front, back) = self.as_slices();
let mut buf = HeapCircularBuffer::<T>::with_capacity(self.capacity());
buf.extend_from_slice(front);
buf.extend_from_slice(back);
buf.into_boxed_circular_buffer()
}
}