#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unstable", feature(maybe_uninit_slice))]
#![cfg_attr(feature = "unstable", feature(maybe_uninit_write_slice))]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(unreachable_pub)]
#![warn(unused_qualifications)]
#![doc(test(attr(deny(warnings))))]
mod drain;
mod iter;
#[cfg(feature = "std")]
mod io;
#[cfg(any(feature = "embedded-io", feature = "embedded-io-async"))]
mod embedded_io;
#[cfg(test)]
mod tests;
use core::cmp::Ordering;
use core::fmt;
use core::hash::Hash;
use core::hash::Hasher;
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;
pub use crate::drain::Drain;
pub use crate::iter::IntoIter;
pub use crate::iter::Iter;
pub use crate::iter::IterMut;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::boxed::Box;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;
#[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)
}
#[inline]
const unsafe fn slice_assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T] {
#[cfg(feature = "unstable")]
unsafe {
slice.assume_init_ref()
}
#[cfg(not(feature = "unstable"))]
unsafe {
&*(slice as *const [MaybeUninit<T>] as *const [T])
}
}
#[inline]
unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
#[cfg(feature = "unstable")]
unsafe {
slice.assume_init_mut()
}
#[cfg(not(feature = "unstable"))]
unsafe {
&mut *(slice as *mut [MaybeUninit<T>] as *mut [T])
}
}
pub struct CircularBuffer<const N: usize, T> {
size: usize,
start: usize,
items: [MaybeUninit<T>; N],
}
impl<const N: usize, T> CircularBuffer<N, T> {
#[inline]
#[must_use]
pub const fn new() -> Self {
#[cfg(feature = "unstable")]
{
Self {
size: 0,
start: 0,
items: [const { MaybeUninit::uninit() }; N],
}
}
#[cfg(not(feature = "unstable"))]
{
Self {
size: 0,
start: 0,
items: unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() },
}
}
}
#[must_use]
#[cfg(feature = "alloc")]
pub fn boxed() -> Box<Self> {
let mut uninit: Box<MaybeUninit<Self>> = Box::new_uninit();
let ptr = uninit.as_mut_ptr();
unsafe {
core::ptr::addr_of_mut!((*ptr).size).write(0);
core::ptr::addr_of_mut!((*ptr).start).write(0);
uninit.assume_init()
}
}
#[inline]
pub const fn len(&self) -> usize {
self.size
}
#[inline]
pub const fn capacity(&self) -> usize {
N
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.size == 0
}
#[inline]
pub const fn is_full(&self) -> bool {
self.size == N
}
#[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<'_, N, T>
where
R: RangeBounds<usize>,
{
Drain::over_range(self, range)
}
pub fn make_contiguous(&mut self) -> &mut [T] {
if N == 0 || self.size == 0 {
return &mut [];
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
let start = self.start;
let end = add_mod(self.start, self.size, N);
let slice = if start < end {
&mut self.items[start..end]
} else {
self.start = 0;
self.items.rotate_left(start);
&mut self.items[..self.size]
};
unsafe { slice_assume_init_mut(slice) }
}
#[inline]
pub fn as_slices(&self) -> (&[T], &[T]) {
if N == 0 || self.size == 0 {
return (&[], &[]);
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
let start = self.start;
let end = add_mod(self.start, self.size, N);
let (front, back) = if start < end {
(&self.items[start..end], &[][..])
} else {
let (back, front) = self.items.split_at(start);
(front, &back[..end])
};
unsafe { (slice_assume_init_ref(front), slice_assume_init_ref(back)) }
}
#[inline]
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
if N == 0 || self.size == 0 {
return (&mut [][..], &mut [][..]);
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
let start = self.start;
let end = add_mod(self.start, self.size, N);
let (front, back) = if start < end {
(&mut self.items[start..end], &mut [][..])
} else {
let (back, front) = self.items.split_at_mut(start);
(front, &mut back[..end])
};
unsafe { (slice_assume_init_mut(front), slice_assume_init_mut(back)) }
}
#[inline]
fn front_maybe_uninit_mut(&mut self) -> &mut MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.start < N, "start out-of-bounds");
&mut self.items[self.start]
}
#[inline]
const fn front_maybe_uninit(&self) -> &MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
&self.items[self.start]
}
#[inline]
const fn back_maybe_uninit(&self) -> &MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let back = add_mod(self.start, self.size - 1, N);
&self.items[back]
}
#[inline]
fn back_maybe_uninit_mut(&mut self) -> &mut MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let back = add_mod(self.start, self.size - 1, N);
&mut self.items[back]
}
#[inline]
const fn get_maybe_uninit(&self, index: usize) -> &MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(index < N, "index out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let index = add_mod(self.start, index, N);
&self.items[index]
}
#[inline]
fn get_maybe_uninit_mut(&mut self, index: usize) -> &mut MaybeUninit<T> {
debug_assert!(self.size > 0, "empty buffer");
debug_assert!(index < N, "index out-of-bounds");
debug_assert!(self.start < N, "start out-of-bounds");
let index = add_mod(self.start, index, N);
&mut self.items[index]
}
#[inline]
fn slices_uninit_mut(&mut self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
if N == 0 {
return (&mut [][..], &mut [][..]);
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
let start = self.start;
let end = add_mod(start, self.size, N);
if end < start {
(&mut self.items[end..start], &mut [][..])
} else {
let (left, right) = self.items.split_at_mut(end);
let left = &mut left[..start];
(right, left)
}
}
#[inline]
fn inc_start(&mut self) {
debug_assert!(self.start < N, "start out-of-bounds");
self.start = add_mod(self.start, 1, N);
}
#[inline]
fn dec_start(&mut self) {
debug_assert!(self.start < N, "start out-of-bounds");
self.start = sub_mod(self.start, 1, N);
}
#[inline]
fn inc_size(&mut self) {
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(self.size < N, "size at capacity limit");
self.size += 1;
}
#[inline]
fn dec_size(&mut self) {
debug_assert!(self.size > 0, "size is 0");
self.size -= 1;
}
#[inline]
unsafe fn drop_range(&mut self, range: Range<usize>) {
if range.is_empty() {
return;
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
debug_assert!(range.start < self.size, "start of range out-of-bounds");
debug_assert!(range.end <= self.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.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(slice_assume_init_mut(self.0));
}
}
}
let drop_from = add_mod(self.start, range.start, N);
let drop_to = add_mod(self.start, range.end, N);
let (right, left) = if drop_from < drop_to {
(&mut self.items[drop_from..drop_to], &mut [][..])
} else {
let (left, right) = self.items.split_at_mut(drop_from);
let left = &mut left[..drop_to];
(right, left)
};
let _left = Dropper(left);
let _right = Dropper(right);
}
#[inline]
pub fn back(&self) -> Option<&T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.back_maybe_uninit().assume_init_ref() })
}
#[inline]
pub fn back_mut(&mut self) -> Option<&mut T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.back_maybe_uninit_mut().assume_init_mut() })
}
#[inline]
pub fn front(&self) -> Option<&T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.front_maybe_uninit().assume_init_ref() })
}
#[inline]
pub fn front_mut(&mut self) -> Option<&mut T> {
if N == 0 || self.size == 0 {
return None;
}
Some(unsafe { self.front_maybe_uninit_mut().assume_init_mut() })
}
#[inline]
pub fn get(&self, index: usize) -> Option<&T> {
if N == 0 || index >= self.size {
return None;
}
Some(unsafe { self.get_maybe_uninit(index).assume_init_ref() })
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if N == 0 || index >= self.size {
return None;
}
Some(unsafe { self.get_maybe_uninit_mut(index).assume_init_mut() })
}
#[inline]
pub fn nth_front(&self, index: usize) -> Option<&T> {
self.get(index)
}
#[inline]
pub fn nth_front_mut(&mut self, index: usize) -> Option<&mut T> {
self.get_mut(index)
}
#[inline]
pub fn nth_back(&self, index: usize) -> Option<&T> {
let index = self.size.checked_sub(index)?.checked_sub(1)?;
self.get(index)
}
#[inline]
pub fn nth_back_mut(&mut self, index: usize) -> Option<&mut T> {
let index = self.size.checked_sub(index)?.checked_sub(1)?;
self.get_mut(index)
}
pub fn push_back(&mut self, item: T) -> Option<T> {
if N == 0 {
return Some(item);
}
if self.size >= N {
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 fn try_push_back(&mut self, item: T) -> Result<(), T> {
if N == 0 {
return Ok(());
}
if self.size >= N {
Err(item)
} else {
self.inc_size();
self.back_maybe_uninit_mut().write(item);
Ok(())
}
}
pub fn push_front(&mut self, item: T) -> Option<T> {
if N == 0 {
return Some(item);
}
if self.size >= N {
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 fn try_push_front(&mut self, item: T) -> Result<(), T> {
if N == 0 {
return Ok(());
}
if self.size >= N {
Err(item)
} else {
self.inc_size();
self.dec_start();
self.front_maybe_uninit_mut().write(item);
Ok(())
}
}
pub fn pop_back(&mut self) -> Option<T> {
if N == 0 || self.size == 0 {
return None;
}
let back = unsafe { self.back_maybe_uninit().assume_init_read() };
self.dec_size();
Some(back)
}
pub fn pop_front(&mut self) -> Option<T> {
if N == 0 || self.size == 0 {
return None;
}
let front = unsafe { self.front_maybe_uninit().assume_init_read() };
self.dec_size();
self.inc_start();
Some(front)
}
pub fn remove(&mut self, index: usize) -> Option<T> {
if N == 0 || index >= self.size {
return None;
}
let index = add_mod(self.start, index, N);
let back_index = add_mod(self.start, self.size - 1, N);
let item = unsafe { self.items[index].assume_init_read() };
unsafe {
let ptr = self.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), N - index - 1);
ptr::copy(ptr, ptr.add(N - 1), 1);
ptr::copy(ptr.add(1), ptr, back_index);
}
}
self.dec_size();
Some(item)
}
pub fn swap(&mut self, i: usize, j: usize) {
assert!(i < self.size, "i index out-of-bounds");
assert!(j < self.size, "j index out-of-bounds");
if i != j {
let i = add_mod(self.start, i, N);
let j = add_mod(self.start, j, N);
unsafe { ptr::swap_nonoverlapping(&mut self.items[i], &mut self.items[j], 1) };
}
}
pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
if index >= self.size {
return None;
}
self.swap(index, self.size - 1);
self.pop_back()
}
pub fn swap_remove_front(&mut self, index: usize) -> Option<T> {
if index >= self.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 N == 0 || self.size == N {
return;
}
while self.size < N - 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 N == 0 {
return;
}
while self.size < N {
self.push_back(f());
}
}
pub fn truncate_back(&mut self, len: usize) {
if N == 0 || len >= self.size {
return;
}
let drop_range = len..self.size;
unsafe { self.drop_range(drop_range) };
self.size = len;
}
pub fn truncate_front(&mut self, len: usize) {
if N == 0 || len >= self.size {
return;
}
let drop_len = self.size - len;
let drop_range = 0..drop_len;
unsafe { self.drop_range(drop_range) };
self.start = add_mod(self.start, drop_len, N);
self.size = len;
}
#[inline]
pub fn clear(&mut self) {
self.truncate_back(0)
}
}
impl<const N: usize, T> CircularBuffer<N, T>
where
T: Clone,
{
pub fn extend_from_slice(&mut self, other: &[T]) {
if N == 0 {
return;
}
debug_assert!(self.start < N, "start out-of-bounds");
debug_assert!(self.size <= N, "size out-of-bounds");
#[cfg(not(feature = "unstable"))]
fn write_uninit_slice_cloned<T: Clone>(dst: &mut [MaybeUninit<T>], src: &[T]) {
struct Guard<'a, T> {
dst: &'a mut [MaybeUninit<T>],
initialized: usize,
}
impl<T> Drop for Guard<'_, T> {
fn drop(&mut self) {
let initialized = &mut self.dst[..self.initialized];
unsafe {
let initialized =
&mut *(initialized as *mut [MaybeUninit<T>] as *mut [T]);
ptr::drop_in_place(initialized);
}
}
}
debug_assert_eq!(dst.len(), src.len());
let len = dst.len();
let mut guard = Guard {
dst,
initialized: 0,
};
#[allow(clippy::needless_range_loop)]
for i in 0..len {
guard.dst[i].write(src[i].clone());
guard.initialized += 1;
}
mem::forget(guard);
}
if other.len() < N {
let free_size = N - self.size;
let final_size = if other.len() < free_size {
self.size + other.len()
} else {
self.truncate_front(N - other.len());
N
};
let (right, left) = self.slices_uninit_mut();
let write_len = core::cmp::min(right.len(), other.len());
#[cfg(feature = "unstable")]
right[..write_len].write_clone_of_slice(&other[..write_len]);
#[cfg(not(feature = "unstable"))]
write_uninit_slice_cloned(&mut right[..write_len], &other[..write_len]);
let other = &other[write_len..];
debug_assert!(left.len() >= other.len());
let write_len = other.len();
#[cfg(feature = "unstable")]
left[..write_len].write_clone_of_slice(other);
#[cfg(not(feature = "unstable"))]
write_uninit_slice_cloned(&mut left[..write_len], other);
self.size = final_size;
} else {
self.clear();
self.start = 0;
let other = &other[other.len() - N..];
debug_assert_eq!(self.items.len(), other.len());
#[cfg(feature = "unstable")]
self.items.write_clone_of_slice(other);
#[cfg(not(feature = "unstable"))]
write_uninit_slice_cloned(&mut self.items, other);
self.size = N;
}
}
#[must_use]
#[cfg(feature = "alloc")]
pub fn to_vec(&self) -> Vec<T> {
let mut vec = Vec::with_capacity(self.size);
vec.extend(self.iter().cloned());
debug_assert_eq!(vec.len(), self.size);
vec
}
}
impl<const N: usize, T> Default for CircularBuffer<N, T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<const N: usize, const M: usize, T> From<[T; M]> for CircularBuffer<N, T> {
fn from(mut arr: [T; M]) -> Self {
#[cfg(feature = "unstable")]
let mut elems = [const { MaybeUninit::uninit() }; N];
#[cfg(not(feature = "unstable"))]
let mut elems = unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() };
let arr_ptr = &arr as *const T as *const MaybeUninit<T>;
let elems_ptr = &mut elems as *mut MaybeUninit<T>;
let size = if N >= M { M } else { N };
unsafe {
ptr::copy_nonoverlapping(arr_ptr.add(M - size), elems_ptr, size);
}
unsafe {
ptr::drop_in_place(&mut arr[..M - size]);
}
mem::forget(arr);
Self {
size,
start: 0,
items: elems,
}
}
}
impl<const N: usize, T> FromIterator<T> for CircularBuffer<N, T> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
let mut buf = Self::new();
iter.into_iter().for_each(|item| {
buf.push_back(item);
});
buf
}
}
impl<const N: usize, T> Extend<T> for CircularBuffer<N, 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, const N: usize, T> Extend<&'a T> for CircularBuffer<N, 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<const N: usize, T> Index<usize> for CircularBuffer<N, T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
self.get(index).expect("index out-of-bounds")
}
}
impl<const N: usize, T> IndexMut<usize> for CircularBuffer<N, T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).expect("index out-of-bounds")
}
}
impl<const N: usize, T> IntoIterator for CircularBuffer<N, T> {
type Item = T;
type IntoIter = IntoIter<N, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
impl<'a, const N: usize, T> IntoIterator for &'a CircularBuffer<N, T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
impl<const N: usize, const M: usize, T, U> PartialEq<CircularBuffer<M, U>> for CircularBuffer<N, T>
where
T: PartialEq<U>,
{
fn eq(&self, other: &CircularBuffer<M, U>) -> bool {
if self.len() != other.len() {
return false;
}
let (a_left, a_right) = self.as_slices();
let (b_left, b_right) = other.as_slices();
match a_left.len().cmp(&b_left.len()) {
Ordering::Less => {
let x = a_left.len();
let y = b_left.len() - x;
a_left[..] == b_left[..x]
&& a_right[..y] == b_left[x..]
&& a_right[y..] == b_right[..]
}
Ordering::Greater => {
let x = b_left.len();
let y = a_left.len() - x;
a_left[..x] == b_left[..]
&& a_left[x..] == b_right[..y]
&& a_right[..] == b_right[y..]
}
Ordering::Equal => {
debug_assert_eq!(a_left.len(), b_left.len());
debug_assert_eq!(a_right.len(), b_right.len());
a_left == b_left && a_right == b_right
}
}
}
}
impl<const N: usize, T> Eq for CircularBuffer<N, T> where T: Eq {}
impl<const N: usize, T, U> PartialEq<[U]> for CircularBuffer<N, T>
where
T: PartialEq<U>,
{
fn eq(&self, other: &[U]) -> bool {
if self.len() != other.len() {
return false;
}
let (a_left, a_right) = self.as_slices();
let (b_left, b_right) = other.split_at(a_left.len());
debug_assert_eq!(a_left.len(), b_left.len());
debug_assert_eq!(a_right.len(), b_right.len());
a_left == b_left && a_right == b_right
}
}
impl<const N: usize, const M: usize, T, U> PartialEq<[U; M]> for CircularBuffer<N, T>
where
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[U; M]) -> bool {
self == &other[..]
}
}
impl<'a, const N: usize, T, U> PartialEq<&'a [U]> for CircularBuffer<N, T>
where
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&'a [U]) -> bool {
self == *other
}
}
impl<'a, const N: usize, T, U> PartialEq<&'a mut [U]> for CircularBuffer<N, T>
where
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&'a mut [U]) -> bool {
self == *other
}
}
impl<'a, const N: usize, const M: usize, T, U> PartialEq<&'a [U; M]> for CircularBuffer<N, T>
where
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&'a [U; M]) -> bool {
self == *other
}
}
impl<'a, const N: usize, const M: usize, T, U> PartialEq<&'a mut [U; M]> for CircularBuffer<N, T>
where
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&'a mut [U; M]) -> bool {
self == *other
}
}
impl<const N: usize, const M: usize, T, U> PartialOrd<CircularBuffer<M, U>> for CircularBuffer<N, T>
where
T: PartialOrd<U>,
{
fn partial_cmp(&self, other: &CircularBuffer<M, U>) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<const N: usize, T> Ord for CircularBuffer<N, T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other.iter())
}
}
impl<const N: usize, T> Hash for CircularBuffer<N, T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.size.hash(state);
self.iter().for_each(|item| item.hash(state));
}
}
impl<const N: usize, T> Clone for CircularBuffer<N, T>
where
T: Clone,
{
fn clone(&self) -> Self {
Self::from_iter(self.iter().cloned())
}
fn clone_from(&mut self, other: &Self) {
self.clear();
self.extend(other.iter().cloned());
}
}
impl<const N: usize, T> Drop for CircularBuffer<N, T> {
#[inline]
fn drop(&mut self) {
self.clear();
}
}
impl<const N: usize, T> fmt::Debug for CircularBuffer<N, T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish()
}
}